Skip to content

Commit

Permalink
Fix bug with immutable entities and transaction cache (#665)
Browse files Browse the repository at this point in the history
Evict entities value from the current transaction cache on force update of immutable entities,
so that the next read of this entity using DAO API would return actual data from the DB
  • Loading branch information
dsdolzhenko authored and Tapac committed Oct 26, 2019
1 parent 51eed97 commit 71e892c
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,12 @@ abstract class ImmutableEntityClass<ID:Comparable<ID>, out T: Entity<ID>>(table:
table.update({ table.id eq entity.id }) {
it[column] = value
}

/* Evict the entity from the current transaction entity cache,
so that the next read of this entity using DAO API would return
actual data from the DB */

TransactionManager.currentOrNull()?.entityCache?.remove(table, entity)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package org.jetbrains.exposed.sql.tests.shared

import org.jetbrains.exposed.dao.*
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.tests.DatabaseTestsBase
import org.jetbrains.exposed.sql.transactions.transaction
import org.junit.Test

class ImmutableEntityTest : DatabaseTestsBase() {

object Schema {
object Organization : IdTable<Long>() {
override val id = long("id").autoIncrement().primaryKey().entityId()
val name = varchar("name", 256)
val etag = long("etag").default(0)
}
}

class EOrganization(id: EntityID<Long>) : Entity<Long>(id) {
companion object : ImmutableEntityClass<Long, EOrganization>(Schema.Organization, EOrganization::class.java)

val name by Schema.Organization.name
val etag by Schema.Organization.etag
}

class ECachedOrganization(id: EntityID<Long>) : Entity<Long>(id) {
companion object : ImmutableCachedEntityClass<Long, ECachedOrganization>(Schema.Organization, ECachedOrganization::class.java)

val name by Schema.Organization.name
val etag by Schema.Organization.etag
}

@Test fun immutableEntityReadAfterUpdate() {
withTables(Schema.Organization) {
db.useNestedTransactions = true

transaction {
Schema.Organization.insert {
it[name] = "JetBrains"
it[etag] = 0
}
}

transaction {
val org = EOrganization.all().single()

EOrganization.forceUpdateEntity(org, Schema.Organization.etag, 1)

assertEquals(1, EOrganization.all().single().etag)
}
}
}

@Test fun immutableEntityCacheInvalidation() {
withTables(Schema.Organization) {
db.useNestedTransactions = true

transaction {
Schema.Organization.insert {
it[name] = "JetBrains"
it[etag] = 0
}
}

transaction {
Schema.Organization.update {
it[name] = "JetBrains Inc."
}
}

transaction {
val org = ECachedOrganization.all().single()

ECachedOrganization.forceUpdateEntity(org, Schema.Organization.name, "JetBrains Gmbh")

Schema.Organization.update {
it[etag] = 1
}

// Populate _cachedValues in ImmutableCachedEntityClass with inconsistent entity value
val updatedOrg = ECachedOrganization.all().single()
}

transaction {
val org = ECachedOrganization.all().single()

assertEquals("JetBrains Gmbh", org.name)
assertEquals(1, org.etag)
}
}
}
}

0 comments on commit 71e892c

Please sign in to comment.