ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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


M
ManuPK

这是来自 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
H
Hadi J

我发现这个注释也很有用:休眠注释中的 @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。它甚至有什么不同吗?
我认为一个表将是原始 pk 的“所有者”(具有 @Id@GeneratedValue@Column 的那个)并且与另一个表有一个 @OneToOne@JoinColumn,另一个表将有 @MapsId 。但是,如果您想先插入“其他表”,这可能行不通。
关于这种使用方式的好文章(使用另一个表中的 id 作为其他实体的 id)在这里 vladmihalcea.com/…
但是,如果您想从已取消的交易中过滤掉交易......这是一个常见的原因。这如何更有效率?我的意思是对于 SQL,您只需为 TRANSACTION.fk_cancelled_id 说 NOT NULL,但在这种情况下,将是更多操作。
在此特定情况下,通常在基类和表中使用“type”之类的列,您可以在其中确定事务是“cancel”类型还是其他类型。
w
wlfbck

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

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

https://i.stack.imgur.com/CUUE4.png

您的实体将是这样的(伪 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 CustomerByConsultantPk implements Serializable {
    
    private Integer customerId;

    private Integer consultantId;
}

@Entity
public class CustomerByConsultant{
   
   @EmbeddedId
   private CustomerByConsultantPk id = new CustomerByConsultantPk();
   
   @MapsId("customerId")
   @JoinColumn(insertable = false, updatable = false)
   private Customer customer;

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

通过这种方式映射,每当您保存顾问时,JPA 都会在 EmbeddableId 中自动插入 CustomerConsultant id。因此您无需手动创建 CustomerByConsultantPk


B
BERGUIGA Mohamed Amine

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


J
Janac Meena

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