外键的复合主键中的共享字段

时间:2018-05-28 15:18:32

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

我的数据库中有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

对于PersonsBooks Borrows中的library_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;
}

是否可以使用[{1}}和Borrow的共享 library_code 列实现PersonId这样的实体,怎么做?

BookId

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

1 个答案:

答案 0 :(得分: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的唯一方法是为其提供Person和{{1}的标识符},这具有逻辑意义,因为BookPersonBook对象必须先存在。

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

Library

Hibernate将负责操纵代码,以便根据需要从非公共范围正确访问所需内容,同时让限制范围指示您如何使用该对象。