我正在尝试使用jOOQ和Kotlin并看过一些教程和文档,看起来非常好。
但如果jOOQ有一些非常烦人的东西就是代码生成。这似乎太复杂了,最终无法维持。我决定创建自己的表模型(类似于hibernate的工作原理)。
我创建了两个表模型:
用户
data class User(
val id: String = UUID.randomUUID().toString(),
val name: String,
val email: String,
val password: String? = null
) {
companion object {
val TABLE: Table<Record> = DSL.table("user")
val ID: Field<String> = DSL.field("id", String::class.java)
val USER_NAME: Field<String> = DSL.field("user_name", String::class.java)
val EMAIL: Field<String> = DSL.field("email", String::class.java)
val PASSWORD: Field<String> = DSL.field("password", String::class.java)
}
}
关注
data class Followers(
val id: String,
val followerId: String,
val userId: String
) {
companion object {
val TABLE: Table<Record> = DSL.table("followers")
val ID: Field<String> = DSL.field("id", String::class.java)
val FOLLOWER_ID: Field<String> = DSL.field("follower_id", String::class.java)
val USER_ID: Field<String> = DSL.field("user_id", String::class.java)
}
}
当我做了一些简单的SQL语句并且它运行得很好时,但是当我尝试下一个语句时,我会遇到异常。
return dsl.select().from(u.TABLE)
.rightJoin(f.TABLE).on(u.ID.eq(f.FOLLOWER_ID))
.where(u.ID.eq(id)).fetch().into(User::class.java)
此代码的预期声明是:
select *
from user u
right outer join followers f
on u.id = f.follower_id
where u.id = 'e30919bf-5f76-11e8-8c96-701ce7e27f83';
但是我从这段代码中得到的陈述是:
select *
from user
right outer join followers
on id = follower_id
where id = 'e30919bf-5f76-11e8-8c96-701ce7e27f83'
当然,这给了我(理所当然)在where子句中的错误列'id'是不明确的
提出了几个问题:
select
没有转换为正确的SQL语句?我做错了什么?答案 0 :(得分:15)
我似乎太复杂了,最终无法维持。 所以,我决定创建自己的表模型(类似于hibernate的工作方式)。
你(可能)正在经历痛苦和痛苦的漫长道路。首先,您现在需要考虑数据库迁移,最好使用数据库的DDL语言。这意味着,从长远来看,您的数据数据库模型应该比您的客户端模型更重要。实际上,您的客户端模型是数据库模型的副本,而不是您想要独立维护的内容。有了这种心态,让代码生成器从数据库模型生成客户端模型更合理,反之亦然。
当然,当你启动一个项目时,Hibernate也会使客户端变得容易。然而,一旦你开始生产,你将必须迁移你的数据库,然后这个模型将破裂。你首先回到数据库,现在已经开始设置所有内容了。
所以,不。代码生成可能会引入一些复杂性现在,但与您创建自己的表模型相比,将更容易维护。
I've written up a longer blog post about this topic, here
return dsl.select().from(u.TABLE) .rightJoin(f.TABLE).on(u.ID.eq(f.FOLLOWER_ID)) .where(u.ID.eq(id)).fetch().into(User::class.java)
此代码的预期声明是:[...]
嗯,这取决于u
和f
是什么。你不能只是将你的Kotlin引用重命名为你的表,并期望jOOQ知道它们的含义。即你可能创建了如下引用:
val u = User.TABLE;
val f = Follower.TABLE;
如果这就是你创建引用的方式,那么这两件事就是按照身份相同的事情。 jOOQ并没有神奇地对你的Kotlin代码进行反向工程,以发现你想要别名你的表。你必须告诉jOOQ:
val u = User.TABLE.as("u");
val f = Follower.TABLE.as("f");
但现在你还没完成。您使用plain SQL API构造了User.TABLE
引用,这意味着jOOQ的运行时不知道该表中的列。您不能再从别名表引用这些列,因为纯SQL表的别名表的类型是Table<?>
,而不是User
。
当然,您可以创建TableImpl
个实例并在TableImpl
实例中注册所有列 - 就像代码生成器一样。在这种情况下,您将拥有与它们关联的表和列,并且即使使用别名表也可以使用它们安全地键入。
所有这些东西都是由生成的代码自动处理的,我建议你再次使用jOOQ。任何人都不会将代码生成器与jOOQ一起使用的主要原因是因为数据模型是动态的,即在编译时不知道。否则,您只需要自动重复代码生成器已为您完成的大量工作。而且,如前所述,当您开始迁移架构时,您将在以后做更多工作。