es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Cómo acceder al campo de fecha y hora fuera de una transacción con Kotlin Exposed.

Tengo una configuración expuesta al estilo DAO con una columna datetime y quiero acceder a ella después de haber recibido la fila del esquema.

Tabla:

object Entries : IntIdTable() {
    val date = datetime(name = "date").nullable()
}

Entidad:

class Entry(id: EntityID<Int>) : IntEntity(id) {
    companion object : EntityClass<Entry>(Entries)

    var date by Entries.date
}

DAO:

object DB {
    private val pool = BasicDataSource()
    private val database: Database

    init {
        pool.url = "jdbc:mysql://127.0.0.1:3306/test"
        pool.driverClassName = "com.mysql.cj.jdbc.Driver"
        pool.username = "user"
        pool.password = "secret"

        pool.minIdle = 5
        pool.maxIdle = 10

        database = Database.connect(pool)
    }

    infix fun <T> query(block: DB.() -> T): T {
        return transaction {
            block.invoke(this@DB)
        }
    }
}

Main:

fun main() {
    val entry = DB.query {
        Entry.all().single() // Solo hay una fila en este punto
    }

    println(entry.date) //! Se produce un error en esta línea
}

Lanza una excepción java.lang.IllegalStateException: No hay transacción en contexto.. Cuando muevo el println dentro de la transacción, funciona como se esperaba. Si cambio el tipo de la columna a varchar y espero un string, funciona en ambos casos.

¿Cómo puedo obtener la fecha fuera de la transacción? Creo que funcionaba en algunas versiones anteriores, pero no estoy seguro.

Tags:  ,

Answer

  1. Avatar for davy.ai

    La razón por la que estás obteniendo el error java.lang.IllegalStateException: No hay transacción en contexto es porque la propiedad date de la entidad Entry se inicializa de forma perezosa dentro de un contexto de transacción.

    Cuando llamas a Entry.all().single(), se crea la instancia de Entry, pero sus propiedades aún no están inicializadas. Cuando intentas acceder a entry.date fuera del contexto de transacción, el método getter de la propiedad date intenta acceder a la base de datos, pero no hay un contexto de transacción disponible.

    Para obtener la fecha fuera de la transacción, puedes hacer lo siguiente:

    1. Cargar de forma inmediata la propiedad date dentro del contexto de transacción:
      fun main() {
         val entry = DB.query {
             Entry.all().single().apply { date } // carga de forma inmediata la propiedad date
         }
      
         println(entry.date) // debería funcionar ahora
      }
      

      El bloque .apply { date } carga la propiedad date de la entidad Entry dentro del contexto de transacción, de manera que se inicializa de forma inmediata antes de que termine la transacción.

    2. Inicializar manualmente la propiedad date fuera del contexto de transacción:

      fun main() {
         val entry = DB.query {
             Entry.all().single() // obtiene la entrada dentro del contexto de transacción
         }
      
         entry.date // inicializa la propiedad date fuera del contexto de transacción
      
         println(entry.date) // debería funcionar ahora
      }
      

      Aquí, estamos obteniendo la entidad Entry dentro del contexto de transacción y luego inicializando la propiedad date fuera del contexto de transacción. Esto cargará de forma inmediata la propiedad date y te permitirá acceder a ella fuera de la transacción.

    Vale la pena mencionar que aunque la opción 2 funcione, generalmente no se recomienda acceder a propiedades perezosas fuera de un contexto de transacción, ya que puede conducir a comportamientos inesperados y problemas de rendimiento.

Comments are closed.