如何使用eBean和Kotlin来表示带有额外字段的连接表?

我正在从规范作者/ book多对多关系示例向book_author表添加字段“角色”:

create table author ( id bigint auto_increment not null, name varchar(255), constraint pk_author primary key (id) ); create table book ( id bigint auto_increment not null, title varchar(255), constraint pk_book primary key (id) ); create table book_author ( book_id bigint not null, author_id bigint not null, role varchar(255), constraint pk_book_author primary key (book_id,author_id) ); 

如果我将代理主键( id bigint auto_increment not null )添加到book_author表中,我只能得到eBean很好地玩这个。 但我不想这样做,因为:

  • book_idauthor_id的组合必须是唯一的
  • 该表需要在book_idauthor_id 索引
  • 代理键作为不可变的唯一标识符是有意义的。 在这种情况下,复合自然键执行相同的作用 – 如果删除了与book_author中的记录匹配的ID的作者或作者,则也应删除book_author记录(在删除级联上)。

总之,这是一个复合主键的目的。 实际上,如果book_author上没有role字段, eBean会正确地生成表格,而不会生成任何相应的Kotlin / Java类 。

这是我在Kotlin代码上的最佳尝试(我认为Java会有同样的问题):

 // Puts an ID field (surrogate key) on tables that extend this. @MappedSuperclass abstract class BaseModel { @Id var id:Long = 0 } @Entity class Author(@Column var name: String): BaseModel() { @OneToMany(mappedBy = "authors") val books:MutableList<Book> = mutableListOf() } @Entity class Book(@Column var title:String) : BaseModel() { @OneToMany(mappedBy = "book") // mapped in both directions! val authors:MutableList<Author> = mutableListOf() } // BREAKS: missing the primary key. // BREAKS: book.getBookAuthors() always returns zero // DOESNT INITIALIZE PROPERLY: ebean.find(BookAuthor.class) @Entity @Table(uniqueConstraints = arrayOf(UniqueConstraint(columnNames = arrayOf("book_id", "author_id")))) class BookAuthor(@ManyToOne @Key val book:Book, @ManyToOne @Key val author:Author) { @Column var role:String = "" } 

以下是db-create-all.sql中book_author的样子:

 create table book_author ( role varchar(255), book_id bigint, author_id bigint, constraint uq_book_author_author_id_book_id unique (author_id,book_id) ); alter table book_author_assoc add constraint fk_book_author_assoc_book_id foreign key (book_id) references book (id) on delete restrict on update restrict; create index ix_book_author_assoc_book_id on book_author_assoc (book_id); alter table book_author_assoc add constraint fk_book_author_assoc_author_id foreign key (author_id) references author (id) on delete restrict on update restrict; create index ix_book_author_assoc_author_id on book_author_assoc (author_id); 

作为一个解决方法(对于类似的表),我刚刚使BookAuthor扩展BaseModel ,它将一个id字段添加到BookAuthor。 那么一切正常。 但这样做只是感觉错了。

非常类似的问题: 无法在PLAY 2.0中使用外键创建复合主键

更新:

我遵循JPA复合键教程,并创建了一个@Embeddable复合键类:

 @Embeddable class BookAuthorCompositeKey(@Column var book: Book?, @Column var author: Author?) : Serializable { // Your class must have a no-arq constructor constructor() : this(null, null) override fun equals(other: Any?): Boolean = (other is BookAuthorCompositeKey) && (aook == other.Book) && (author == other.Author) override fun hashCode(): Int { var ret:Int = 0 try { ret += book!!.hashCode() } catch (ignore:NullPointerException) { } try { ret += author!!.hashCode() } catch (ignore:NullPointerException) { } return ret } } 

然后用新课程更新了BookAuthor,并且在书和作者关系上增加了级联:

 @Entity class Author(@Column var name: String): BaseModel() { @OneToMany(cascade = arrayOf(CascadeType.ALL)) // CHANGED val books:MutableList<Book> = mutableListOf() } @Entity class Book(@Column var title:String) : BaseModel() { @OneToMany(cascade = arrayOf(CascadeType.ALL)) // CHANGED val authors:MutableList<Author> = mutableListOf() } @Entity class BookAuthor(@EmbeddedId val back:BookAuthorCompositeKey) { @Column var role:String = "" } 

但是db-create-all.sql现在看起来更糟了 – 它只能引用其中一个表格!

create table book_author(book_id bigint not null,role varchar(255));

嗯…我开始认为eBean需要一个代理键。

Interesting Posts