хтось може пояснити мені @MapsId в сплячому режимі?


81

Хтось може пояснити мені @MapsIdв сплячому режимі? Мені важко це зрозуміти.

Було б чудово, якби це можна було пояснити на прикладі і в яких випадках використання це найбільш застосовне?

Відповіді:


47

Ось гарне пояснення від Object DB .

Позначає атрибут взаємозв'язку ManyToOne або OneToOne, який забезпечує відображення первинного ключа EmbeddedId, атрибута в первинному ключі EmbeddedId або простого первинного ключа батьківської сутності. Елемент 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 тут.


6
Але що в цьому приємного? Навіть без @MapsId можна використати JoinColumn з тим самим ефектом, чи не так? І якщо так, цей приклад насправді не говорить про те, для чого ця анотація насправді корисна.
Максим Гумеров 23.03.18

2
Оскільки обидві сутності матимуть один і той же первинний ключ, сутність із стовпцем, позначеним за допомогою @MapsIdwill у рівні збереження (база даних), має лише стовпець первинного ключа. Ідея полягає в тому, щоб поділити первинний ключ між двома сутностями.
johanwannheden

Що таке первинний ключ EmbeddedId? Чим він відрізняється від звичайного первинного ключа?
sofs1

"Елемент значення вказує атрибут у складеному ключі, якому відповідає атрибут відношення." 1) Що мається на увазі під елементом значення, наведіть приклад? 2) Що таке складений ключ? 3) Що таке атрибут відносин і наведіть приклад?
sofs1

@MaksimGumerov це ефективно, оскільки ви можете отримати його, Dependentпросто знаючи ідентифікатор Employee.
Еммануель Озімосу

26

Я також знайшов цю примітку корисною: @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), і матиме a @OneToOneта @JoinColumnз іншою таблицею, а інша таблиця буде мати @MapsId. Однак це, мабуть, не спрацювало б, якщо спочатку ВСТАВИТИ в "іншу таблицю".
Тонсіч

1
Хороша стаття про такий спосіб використання (використання ідентифікатора з іншої таблиці як ідентифікатора іншої сутності) знаходиться тут vladmihalcea.com/…
Любо

Але якщо ви хочете відфільтрувати транзакції від скасованих .., що є загальною причиною. Як це ефективніше? Я маю на увазі для SQL, вам просто потрібно сказати NOT NULL для TRANSACTION.fk_cancelled_id, але в цьому випадку буде більше операцій.
M_F

У цьому конкретному випадку тут зазвичай використовують стовпець типу "type" у базовому класі та таблиці, де слід визначити, чи має транзакція тип "cancel" або інший.
Тонсіч

3

Як він пояснив Володимиру у своєму підручнику , найкращий спосіб відобразити відносини @OneToOne - це використовувати @MapsId. Таким чином, вам навіть не потрібна двонаправлена ​​асоціація, оскільки ви завжди можете отримати дочірню сутність, використовуючи ідентифікатор батьківської сутності.


2

MapsId дозволяє використовувати один і той же первинний ключ між двома різними сутностями / таблицями. Примітка: коли ви використовуєте MapsId, CASCADE.ALLпрапор стає марним, і вам потрібно буде переконатися, що ваші об’єкти зберігаються вручну.


1

IMHO, найкращий спосіб подумати @MapsId, коли вам потрібно зіставити складений ключ у сутності: m.

Наприклад, клієнт може мати одного або декількох консультантів, а консультант може мати одного або більше клієнтів:

введіть тут опис зображення

І ваші entites будуть приблизно такими (псевдо-код 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 автоматично вставляє Customerта Consultantідентифікує EmbeddableIdкожен раз, коли ви зберігаєте консультанта. Тому вам не потрібно створювати файл вручну ConsultantByConsultantPk.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.