有人可以在休眠状态向我解释@MapsId吗?


Answers:


46

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

指定ManyToOne或OneToOne关系属性,该属性提供EmbeddedId主键,EmbeddedId主键内的属性或父实体的简单主键的映射。值元素指定关系属性所对应的组合键中的属性。如果实体的主键与关系所引用的实体的主键具有相同的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文档


6
但是,这有什么好处呢?即使没有@MapsId,也可以使用JoinColumn达到相同的效果,不是吗?如果是这样,则此示例并不能真正说明此批注的真正好处。
Maksim Gumerov '18

2
由于两个实体将共享相同的主键,因此@MapsId在持久性层(数据库)中具有由will指定的列的实体仅具有主键列。这个想法是在两个实体之间共享主键。
johanwannheden

什么是EmbeddedId主键?与普通主键有何不同?
sofs1

“值元素指定了关系属性所对应的组合键中的属性。” 1)值元素的含义是什么?2)什么是组合键?3)什么是关系属性并举一个例子?
sofs1

@MaksimGumerov的效率很高,因为您Dependent只需知道的标识符即可获取Employee
Emmanuel Osimosu

25

我发现此注释也很有用:@MapsId在休眠注释中,将一列与另一个表的列进行映射。

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

例:

@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。它甚至有所作为吗?
marcus

我认为,一个表将在原有PK(具有的“所有者”@Id@GeneratedValue@Column),并具有@OneToOne@JoinColumn与其他表,其他表会有@MapsId。但是,如果您想先插入“其他表”,则可能无法使用。
托尼克

1
关于这种使用方式的好文章(使用另一个表的ID作为其他实体的ID)在这里vladmihalcea.com/…–
Lubo

但是,如果要从已取消的交易中筛选出交易,这是一个常见原因。效率如何?我的意思是,对于SQL,您只需要对TRANSACTION.fk_cancelled_id说NOT NULL,但在这种情况下,它将进行更多操作。
M_F

在此特定情况下,通常在基类和表中使用诸如“类型”之类的列,您将在其中确定事务是“取消”类型还是其他类型。
凌晨

2

正如他在教程中向Vladimir解释的那样,映射@OneToOne关系的最佳方法是使用@MapsId。这样,您甚至不需要双向关联,因为您始终可以通过使用父实体标识符来获取子实体。


2

通过MapsId,您可以在两个不同的实体/表之间使用相同的主键。注意:当您使用MapsId时,该CASCADE.ALL标志将变得无用,并且需要确保手动保存了您的实体。


1

恕我直言,最好的考虑方法@MapsId是何时需要在: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)
   Customer customer;

   @MapsId("consultantId")
   @JoinColumn(insertable = false, updatable = false)
   Consultant consultant;
}

通过这种方式映射,只要您保存顾问,JPA就会自动在其中插入IDCustomerConsultantID EmbeddableId。因此,您无需手动创建ConsultantByConsultantPk

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.