Сущность не сохраняется в Exposed после метода @Transactional в Spring Boot - PullRequest
0 голосов
/ 20 мая 2018

У меня есть следующие классы DAO

package exposed.example

import org.jetbrains.exposed.dao.EntityID
import org.jetbrains.exposed.dao.UUIDEntity
import org.jetbrains.exposed.dao.UUIDEntityClass
import org.jetbrains.exposed.dao.UUIDTable
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.SchemaUtils
import org.jetbrains.exposed.sql.transactions.transaction
import java.util.*

object CustomerTable: UUIDTable(name = "customer") {
    val name = varchar(name = "name", length = 255).uniqueIndex()
}

class CustomerDAO(id: EntityID<UUID>): UUIDEntity(id) {
    companion object : UUIDEntityClass<CustomerDAO>(CustomerTable)

    var name by CustomerTable.name
}

object OrderTable: UUIDTable(name = "orders") {
    val customer = reference(name = "customer_id", foreign = CustomerTable)
    val product = varchar(name = "product", length = 255)
}

class OrderDAO(id: EntityID<UUID>): UUIDEntity(id) {
    companion object : UUIDEntityClass<OrderDAO>(OrderTable)

    var customer by OrderTable.customer
    var product by OrderTable.product
}

Если я создаю транзакцию вручную, то сущности сохраняются в базе данных, см. Код ниже

fun main(args: Array<String>) {
    Database.connect("jdbc:postgresql://localhost:5432/testdb", driver = "org.postgresql.Driver", user = "test", password = "testpassword")
    transaction {
        SchemaUtils.create(CustomerTable, OrderTable)
        val customer = CustomerDAO.new {
            name = "Alice_${System.currentTimeMillis()}"
        }

        OrderDAO.new {
            this.customer = customer.id
            product = "MegaProduct"
        }
    }
}

Но если я использую то же самоеCustomerDAO и OrderDAO в методе @Transactional в приложении весенней загрузки начинают происходить странные вещи.

package exposed.example

import org.jetbrains.exposed.spring.SpringTransactionManager
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.context.annotation.Bean
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
import org.springframework.transaction.annotation.EnableTransactionManagement
import org.springframework.transaction.annotation.Transactional
import javax.sql.DataSource


open class Service {

    @Transactional
    open fun createCustomer(name: String): CustomerDAO {
        return CustomerDAO.new {
            this.name = name
        }
    }

    @Transactional
    open fun createOrder(customer: CustomerDAO, product: String): OrderDAO {
        return OrderDAO.new {
            this.customer = customer.id
            this.product = product
        }
    }

    @Transactional
    open fun doBoth(name: String, product: String): OrderDAO {
        return createOrder(createCustomer(name), product)
    }

}

@SpringBootApplication
@EnableTransactionManagement
open class App {

    @Bean
    open fun transactionManager(dataSource: DataSource) = SpringTransactionManager(dataSource)

    @Bean // PersistenceExceptionTranslationPostProcessor with proxyTargetClass=false, see https://github.com/spring-projects/spring-boot/issues/1844
    open fun persistenceExceptionTranslationPostProcessor() = PersistenceExceptionTranslationPostProcessor()

    @Bean
    open fun service() = Service()

}

fun main(args: Array<String>) {

    val app = runApplication<App>(*args)
    val service = app.getBean(Service::class.java)

//    val customer = service.createCustomer("Alice1")
//    service.createOrder(customer, "SpringProduct")

    service.doBoth("Bob", "SpringProduct")

}

Создается только customer, но в этом случае не order.Если я раскомментирую две строки выше, то клиент не будет создан, а вторая строка вызовет NPE.

Таким образом, в методе @Transactional сущность сохраняется только в том случае, если на нее ссылается другой или запрашивается.

Как все-таки заставить его сохраняться?

Заранее спасибо,

Ответы [ 2 ]

0 голосов
/ 21 июня 2018

проблема ушла в открытую 0.10.2

0 голосов
/ 21 мая 2018

Пока я нашел этот обходной путь:

@Transactional
    open fun createOrder(customer: CustomerDAO, product: String): OrderDAO {
        val id = OrderTable.insertAndGetId {
            it[this.customer] = customer.id
            it[this.product] = product
        }
        return OrderDAO.findById(id)!!
    }

Но это грязная смесь DSL и DAO API, любое улучшение приветствуется.

...