Java 使用Jooq创建通用存储库

Java 使用Jooq创建通用存储库,java,spring-boot,kotlin,generics,jooq,Java,Spring Boot,Kotlin,Generics,Jooq,我们正在使用JOOQ映射现有数据库。此数据库中的每个表(栏1)共享一组类似的列: resource_id: Int (FK) id: Int (PK) identifier: UUID date_created: DateTime date_modified: DateTime 数据库中有一条适用于所有操作的一般规则,如下所示: select * from table t join resource r on r.id = t.resou

我们正在使用JOOQ映射现有数据库。此数据库中的每个表(栏1)共享一组类似的列:

resource_id:   Int (FK)
id:            Int (PK)
identifier:    UUID
date_created:  DateTime
date_modified: DateTime
数据库中有一条适用于所有操作的一般规则,如下所示:

select   * 
from     table t
join     resource r on r.id = t.resource_id
where    r.is_archived = false 
使用JOOQs生成功能,我可以成功创建一个存储库类,该类实现基本查询操作:


@Repository
class UserRepository(val dsl:DSLContext): IRepository {
    val record = Tables.AUTHENTICATION_USER!!   //generated by jooq
    val resource = Tables.RESOURCE!!            //generated by jooq
    val pojo = AuthenticationUser::class.java   //generated by jooq

    // this is the general query logic that should be applied to all the things
    override fun selectQuery(): SelectConditionStep<Record> {
        return dsl
            .select(record.asterisk())
            .from(record)
            .join(resource).on(resource.ID.eq(record.RESOURCE_ID))
            .where(resource.IS_ARCHIVED.eq(false))
    }

    override fun asyncCount(): Mono<Int> = Mono.fromCallable {
        selectQuery()
            .count()
    }

    fun asyncGetPage(from: Int,
                     size: Int,
                     orderBy: SortField<*> = record.DATE_CREATED.asc(),
    ) = Mono.fromCallable {
        selectQuery()
            .orderBy(orderBy)
            .limit(size)
            .offset(from)
            .fetchInto(pojo)
            .let { Collections.unmodifiableList(it) }
    }
当我尝试使用
表T
执行任何操作时,问题就出现了。由于
T
是一种通用表类型,编译器无法知道字段
id
identifier
resource\u id
date\u created
等,这意味着这样的查询无法编译:

    fun asyncGetAllNonArchived() = 
        dsl
            .select()
            .from(table)
            .where(table.DATE_CREATED > ...)
问题: 有没有一种方法可以告诉编译器或以公共字段可用的方式声明泛型


编辑:感谢下面卢卡斯·埃德的建议。通过调整该解决方案,我们能够创建一个通用存储库

首先,将生成器策略更改为Kotlin,让
可审核的
接口正确动作:)

其次,我们找不到泛型类实现
类型的
记录
类型的方法,因此您必须稍微扩展签名

interface Auditable {
    fun RESOURCE_ID(): TableField<Record, Int> =
        (this as Table<Record>).field("resource_id") as TableField<Record, Int>

    fun ID(): TableField<Record, Int> =
        (this as Table<Record>).field("id") as TableField<Record, Int>

    fun IDENTIFIER(): TableField<Record, UUID> =
        (this as Table<Record>).field("identifier") as TableField<Record, UUID>

    fun DATE_CREATED(): TableField<Record, LocalDateTime> =
        (this as Table<Record>).field("date_created") as TableField<Record, LocalDateTime>

    fun DATE_MODIFIED(): TableField<Record, LocalDateTime> =
        (this as Table<Record>).field("date_modified") as TableField<Record, LocalDateTime>
}


open class GeneralRepository<R, T>(val table: T) where R: Record, T: Table<R>, T: Auditable {
    val resource = Resource.RESOURCE

    fun selectQuery() =
        dsl
            .select(table.asterisk())
            .from(table)
            .join(resource).on(resource.ID.eq(table.RESOURCE_ID()))
            .where(resource.IS_ARCHIVED.eq(false))
接口可审核{
乐趣资源_ID():TableField=
字段(“资源_id”)作为表字段
fun ID():TableField=
字段(“id”)作为TableField
趣味标识符():TableField=
字段(“标识符”)作为TableField
趣味日期_CREATED():TableField=
字段(“创建日期”)作为表格字段
趣味日期_MODIFIED():TableField=
(此为表格)。字段(“修改日期”)为表格字段
}
打开类GeneralRepository(val table:T),其中R:Record,T:table,T:Auditable{
val resource=resource.resource
fun selectQuery()=
数字用户线
.选择(表.asterisk())
.来自(表)
.join(resource).on(resource.ID.eq(table.resource\u ID()))
.where(resource.IS_.eq(false))
然后,您可以轻松实现通用扩展:

class UserRepo: GeneralRepository<UserRecord, User>(table = User.USER) {

    fun getEmail(email: String) = Mono.fromCallable {
        selectQuery().and(table.EMAIL.eq(email))
    }
}
class UserRepo:GeneralRepository(table=User.User){
fun getEmail(email:String)=Mono.fromCallable{
选择query()和(table.EMAIL.eq(EMAIL))
}
}

您可以生成一个界面,提供对以下列的访问:

接口可审核{
乐趣资源\u ID():表字段=
字段(“资源_id”)作为表字段
乐趣ID():表字段=
字段(“id”)作为TableField
趣味标识符():TableField=
字段(“标识符”)作为TableField
乐趣日期\u已创建():TableField=
字段(“创建日期”)作为表格字段
乐趣日期\u修改():表字段=
(此为表格)。字段(“修改日期”)为表格字段
}
然后使用以下命令将接口附加到所有生成的表:


T_*
com.example.Auditable
当前无法在接口中声明属性,因为无法检测是否需要
重写
修饰符,请参阅

但现在这可能已经足够好了。然后您可以创建如下通用条件:

select   * 
from     table t
join     resource r on r.id = t.resource_id
where    r.is_archived = false 
funDateCreatedCondition(表:T,dt:LocalDateTime):条件
其中T:Table,T:Auditable=Table.DATE_CREATED().gt(dt)

您是否知道,您可以在Stack Overflow上为自己的问题提供答案,而不是编辑您的问题。这样,对该问题的未来访问者可能更有帮助