【问题标题】:Shared field in composite primary key for foreign keys外键的复合主键中的共享字段
【发布时间】:2018-11-07 05:27:04
【问题描述】:

我的数据库中有 4 个表:

+-------------+
|Libraries    |
+-------------+ . . . . . _________
|P code       |                   |
+-------------+                   -
      .                           ^
      .                  +---------------+
      |                  |Persons        |
      |                  +---------------+
      -                  |P  name        |
      ^                  |FP library_code|
+-----------------+      +---------------+
|Books            |              .
+-----------------+              .
|P   title        |              |
|FP  library_code |              |
+-----------------+              -
      .                          ^
      .                 +----------------+  
      |                 |Borrows         |
      +_______________|<+----------------+
                        |FP person_name  |
                        |FP book_title   |
                        |FP library_code |
                        +----------------+

P - primary key
FP - foreign primary key

_
^ - foreign key is part of primary key

Borrows 中的PersonsBookslibrary_code 应该相同(共享列)!

我的 java 代码如下:

@Entity
class Library {
    @Id
    private String code;
}

@Embeddable
class PersonId implements Serializable {
    private String name;
    private String library_code;
}

@Entity 
class Person {
    @EmbeddedId 
    private PersonId id;
}

@Embeddable
class BookId implements Serializable {
    private String title;
    private String library_code;
}

@Entity 
class Book {
    @EmbeddedId 
    private BookId id;
}

是否可以使用PersonIdBookId 的共享library_code 列来实现这样的Borrow 实体,如何实现?

@Embeddable
class BorrowId implements Serializable {
    private PersonId person;
    private BookId book;
}

@Entity 
class Borrow {
    @EmbeddedId 
    private BorrowId id;
}

注意:这个问题与数据库模型无关,模型已经提供,我无法更改它,我只需要找到如何将其映射到实体模型的最佳方法。

【问题讨论】:

  • 鉴于您的Borrow PK 是 3 列而不是 4 列(您的可嵌入实现意味着),我不会那样映射它。我只需为Borrow 创建一个可嵌入的 3 列,并根据需要将值复制到其中,而不是想花哨。
  • 我们离开的@Naros 作为备用选项。我们决定,对于我们的应用程序,最好创建问题中描述的结构。
  • 您可以尝试在其中一个内部嵌入件上使用@AttributeOverridelibrary_code 标记为updatable=false,insertable=false,但我不确定这是否足以让持久性提供者不这样做抱怨重复的列名。标识符的某些方面确实会被某些提供程序覆盖(例如,不为空),因为 PK 列为空是没有意义的。
  • @Naros 我们将使用您的解决方案,因为我们没有找到更好的解决方案。但我仍然会在这里等待答案:)

标签: hibernate jpa spring-data spring-data-jpa


【解决方案1】:

正如我在评论中提到的,您首先可以在这里利用@AttributeOverride

@Embeddable
public class BorrowId implements Serializable {
  private PersonId person;
  @AttributeOverride(
    name = "library_code",
    column = @Column(insertable=false, updatable=false) )
  private BookId book;
  // getter/setter(s) with proper equals/hashcode
}

您可以考虑的另一种选择是从领域驱动设计中提取一个页面:

@Embeddable
public class BorrowId implements Serializable {
  private String person;
  private String book;
  private String libraryCode;

  // Required by JPA
  // notice its package private
  BorrowId() {}

  public BorrowId(PersonId person, BookId book) {
    // validates you are pairing a person and book with same library codes
    assert person.getLibraryCode().equals( book.getLibraryCode() );
    this.person = person.getName();
    this.book = book.getTitle();
    this.libraryCode = person.getLibraryCode();
  }

  // expose all getters as public 
  // expose all setters as non-public 
  // implement proper equals/hashcode
}

后一种解决方案的想法是,我们使用域驱动设计来强制构造BorrowId 的唯一方法是为其提供PersonBook 的标识符,这在逻辑上是有意义的因为PersonBookLibrary 对象必须先存在。

如果你真的想更进一步,构造函数可以是

public BorrowId(Person person, Book book, Library library) {
  assert library.getCode().equals( person.getId().getLibraryCode() );
  assert library.getCode().equals( book.getId().getLibraryCode() );
  this.person = person.getId().getName();
  this.book = book.getId().getTitle();
  this.library = library.getCode();
}

Hibernate 将负责操作代码以根据需要从非公共范围正确访问所需内容,同时让受限范围决定您应该如何使用该对象。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-18
    • 2010-11-09
    • 2014-02-26
    • 1970-01-01
    • 1970-01-01
    • 2013-06-29
    • 1970-01-01
    • 2018-04-07
    相关资源
    最近更新 更多