【问题标题】:can someone please explain me @MapsId in hibernate?有人可以在休眠中向我解释@MapsId吗?
【发布时间】:2012-04-12 23:56:27
【问题描述】:

有人可以在休眠中向我解释@MapsId吗?我很难理解它。

如果可以用一个例子来解释它会很棒,它最适用于什么样的用例?

【问题讨论】:

    标签: java hibernate jpa annotations hibernate-annotations


    【解决方案1】:

    这是来自Object DB 的一个很好的解释。

    指定为 EmbeddedId 主键、EmbeddedId 主键中的属性或父实体的简单主键提供映射的 ManyToOne 或 OneToOne 关系属性。 value 元素指定关系属性对应的复合键中的属性。如果实体的主键与关系引用的实体的主键的Java类型相同,则不指定value属性。

    // parent entity has simple primary key
    
    @Entity
    public class Employee {
       @Id long empId;
       String name;
       ...
    } 
    
    // dependent entity uses EmbeddedId for composite key
    
    @Embeddable
    public class DependentId {
       String name;
       long empid;   // corresponds to primary key type of Employee
    }
    
    @Entity
    public class Dependent {
       @EmbeddedId DependentId id;
        ...
       @MapsId("empid")  //  maps the empid attribute of embedded id
       @ManyToOne Employee emp;
    }
    

    在此处阅读API Docs

    【讨论】:

    • 但是它有什么好处呢?即使没有@MapsId,也可以使用 JoinColumn 达到同样的效果,不是吗?如果是这样,这个例子并不能真正说明这个注释的真正用途。
    • 由于两个实体将共享相同的主键,具有@MapsId 指定列的实体将在持久层(数据库)中只有主键列。这个想法是在两个实体之间共享主键。
    • 什么是 EmbeddedId 主键?和普通的主键有什么区别?
    • "value元素指定了复合键中关系属性所对应的属性。" 1) value元素是什么意思,请举例说明? 2)什么是复合键? 3) 什么是关系属性并举例说明?
    • @MaksimGumerov 这很有效,因为您只需知道Employee 的标识符即可获取Dependent
    【解决方案2】:

    我发现这个注释也很有用:@MapsId in hibernate annotation 将一个列映射到另一个表的列。

    它也可以用来在两个表之间共享相同的主键。

    例子:

    @Entity
    @Table(name = "TRANSACTION_CANCEL")
    public class CancelledTransaction {
        @Id
        private Long id; // the value in this pk will be the same as the
                         // transaction line from transaction table to which 
                         // this cancelled transaction is related
    
        @OneToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "ID_TRANSACTION", nullable = false)
        @MapsId
        private Transaction transaction;
        ....
    }
    
    @Entity
    @Table(name = "TRANSACTION")
    @SequenceGenerator(name = "SQ_TRAN_ID", sequenceName = "SQ_TRAN_ID")
    public class Transaction  {
        @Id
        @GeneratedValue(generator = "SQ_TRAN_ID", strategy = GenerationType.SEQUENCE)
        @Column(name = "ID_TRANSACTION", nullable = false)
        private Long id;
        ...
    }
    

    【讨论】:

    • 我在哪里将@MapsId 放在双向关联中?两个类都应该有@MapsId。它甚至有什么不同吗?
    • 我认为一张表将是原始 pk 的“所有者”(带有 @Id@GeneratedValue@Column 的表)并有一个 @OneToOne@JoinColumn 与另一个表,另一个表将有 @MapsId 。但是,如果您想先插入“其他表”,这可能行不通。
    • 关于这种使用方式的好文章(使用另一个表中的 id 作为其他实体的 id)在这里vladmihalcea.com/…
    • 但是如果你想从取消的交易中过滤掉交易......这是一个常见的原因。这如何更有效率?我的意思是,对于 SQL,您只需为 TRANSACTION.fk_cancelled_id 说 NOT NULL,但在这种情况下,将是更多操作。
    • 在此特定情况下,通常在基类和表中使用“type”之类的列,您可以在其中识别事务是“cancel”类型还是其他类型。
    【解决方案3】:

    恕我直言,考虑 @MapsId 的最佳方式是当您需要在 n:m 实体中映射复合键时。

    例如,一个客户可以有一个或多个顾问,而一个顾问可以有一个或多个客户:

    您的实体将是这样的(伪 Java 代码):

    @Entity
    public class Customer {
       @Id
       private Integer id;
    
       private String name;
    }
    
    @Entity
    public class Consultant {
       @Id
       private Integer id;
    
       private String name;
    
       @OneToMany
       private List<CustomerByConsultant> customerByConsultants = new ArrayList<>();
    
       public void add(CustomerByConsultant cbc) {
          cbc.setConsultant(this);
          this.customerByConsultant.add(cbc);
       }
    }
    
    @Embeddable
    public class ConsultantByConsultantPk implements Serializable {
        
        private Integer customerId;
    
        private Integer consultantId;
    }
    
    @Entity
    public class ConsultantByConsultant {
       
       @EmbeddedId
       private ConsultantByConsultantPk id = new ConsultantByConsultantPk();
       
       @MapsId("customerId")
       @JoinColumn(insertable = false, updatable = false)
       private Customer customer;
    
       @MapsId("consultantId")
       @JoinColumn(insertable = false, updatable = false)
       private Consultant consultant;
    }
    

    以这种方式映射,每当您保存顾问时,JPA 都会自动在 EmbeddableId 中插入 CustomerConsultant id。所以你不需要手动创建ConsultantByConsultantPk

    【讨论】:

      【解决方案4】:

      正如弗拉基米尔在tutorial 中解释的那样,映射@OneToOne 关系的最佳方法是使用@MapsId。这样,您甚至不需要双向关联,因为您始终可以使用父实体标识符获取子实体。

      【讨论】:

        【解决方案5】:

        MapsId 允许您在两个不同的实体/表之间使用相同的主键。注意:当您使用 MapsId 时,CASCADE.ALL 标志变得无用,您需要确保您的实体是手动保存的。

        【讨论】:

          猜你喜欢
          • 2011-05-08
          • 1970-01-01
          • 2012-04-09
          • 2021-02-18
          • 2023-02-08
          • 2011-01-08
          • 2014-04-20
          • 2011-04-24
          • 2011-08-20
          相关资源
          最近更新 更多