Как представить таблицу соединений с дополнительным полем с помощью eBean и Kotlin?

Я добавляю поле «роль» в таблицу 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) ); 

Я могу только получить eBean, чтобы хорошо играть с этим, если я добавлю суррогатный первичный ключ ( id bigint auto_increment not null ) в таблицу book_author . Но я не хочу этого делать, потому что:

  • Сочетание book_id и author_id должно быть уникальным
  • Таблица должна быть проиндексирована на book_id и author_id
  • Суррогатные ключи имеют смысл как неизменные уникальные идентификаторы. В этом случае составной естественный ключ выполняет ту же роль. Если книга или автор с идентификатором, соответствующим записи в book_author, удаляются, запись book_author также должна быть удалена (при удалении каскада).

Короче говоря, это то, для чего предназначен составной первичный ключ. На самом деле, если в book_author нет поля book_author , eBean правильно генерирует таблицу , если я не book_author соответствующий класс Kotlin / Java .

Вот моя лучшая попытка кода Котлина (я думаю, что у 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 = "" } 

Вот как выглядит book_author в db-create-all.sql:

 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 требует суррогатного ключа.

Intereting Posts
Котлин строит, вызывая JVM к ошибке сегментации Kapt + LoganSquare не работает должным образом при сопоставлении Свойство getter напечатано на Supertype вместо внедрения в Kotlin Как использовать AndroidAnnotation @SharedPref с Kotlin Получить пару цифр из списка номеров в Котлин В Kotlin, как мне расширить класс, который имеет несколько конструкторов? Как получить данные Google Fit Step с сервера? @Throws не влияет, когда цель является свойством Генериры Котлина Массив <T> приводит к «Невозможно использовать T как параметр типа reified. Вместо этого используйте класс, но List <T> не делает Kotlin – исключение документа, созданное методом интерфейса kotlin получить представление из заголовка NavigationView Волейбольная библиотека. Где я ошибся с Ответчиком? Расширения и фрагменты Android Kotlin Как установить конфигурации package.json с помощью kotlin-frontend-plugin Как назначить новое значение, если вы устанавливаете setter private в kotlin?