أي شرح يجب أن أستخدمه: idclass أو embeddedid
-
03-07-2019 - |
سؤال
ال JPA
(API Java Persistence) لها طريقتان مختلفتان لتحديد مفاتيح الكيان المركبة: @IdClass
و @EmbeddedId
.
أنا أستخدم كلا التعليقات التوضيحية على كياناتي المعينة ، لكن اتضح أنهما فوضى كبيرة للأشخاص الذين ليسوا على دراية بهم JPA
.
أريد تبني طريقة واحدة فقط لتحديد المفاتيح المركبة. أيهما هو الأفضل حقًا؟ لماذا ا؟
المحلول
أنا أعتبر ذلك @EmbeddedId
ربما يكون أكثر مطوّلة لأنه مع @IdClass
لا يمكنك الوصول إلى كائن المفتاح الأساسي بأكمله باستخدام أي مشغل للوصول إلى الحقل. باستخدام @EmbeddedId
يمكنك أن تفعل مثل هذا:
@Embeddable class EmployeeId { name, dataOfBirth }
@Entity class Employee {
@EmbeddedId EmployeeId employeeId;
...
}
هذا يعطي فكرة واضحة للحقول التي تجعل المفتاح المركب لأنه يتم تجميعها جميعًا في فئة يتم الوصول إليها في مشغل الوصول الميداني.
فرق آخر مع @IdClass
و @EmbeddedId
هو عندما يتعلق الأمر بكتابة HQL:
مع @IdClass
انت تكتب:
select e.name from Employee e
ومع @EmbeddedId
لديك لكتابة:
select e.employeeId.name from Employee e
عليك أن تكتب المزيد من النص لنفس الاستعلام. قد يجادل البعض بأن هذا يختلف عن لغة أكثر طبيعية مثل اللغة التي تروج لها IdClass
. لكن في معظم الأوقات التي تتفهم من الاستعلام أن الحقل المعطى هو جزء من المفتاح المركب هو مساعدة لا تقدر بثمن.
نصائح أخرى
لقد اكتشفت مثيلًا اضطررت فيه إلى استخدام inmbeddedid بدلاً من corclass. في هذا السيناريو ، يوجد جدول انضمام يحتوي على أعمدة إضافية محددة. حاولت حل هذه المشكلة باستخدام IDClass لتمثيل مفتاح الكيان الذي يمثل صفوفًا صريحًا في جدول الانضمام. لم أستطع تشغيلها بهذه الطريقة. والحمد لله "Java Persistence with Hibernate" لديه قسم مخصص لهذا الموضوع. كان أحد الحلول المقترحة مشابهاً جدًا لي ولكنه يستخدم embeddedid بدلاً من ذلك. قمت بنمذجة الأشياء الخاصة بي بعد تصرفها الآن في الكتاب بشكل صحيح.
هناك ثلاث استراتيجيات لاستخدام مفتاح أساسي مركب:
- ضع علامة على ذلك
@Embeddable
وأضف إلى خاصية الكيان من الفئة A@Id
. - أضف إلى خاصية كيانك من الدرجة A
@EmbeddedId
. - أضف خصائص إلى فئة الكيان الخاصة بك لجميع حقولها ، ضع علامة عليها
@Id
، ووضع علامة على فئة الكيان الخاصة بك مع@IdClass
, ، تزويد فئة الفئة الرئيسية الخاصة بك.
استخدام @Id
مع فئة تحمل علامة @Embeddable
هو النهج الأكثر طبيعية. ال @Embeddable
يمكن استخدام TAG للقيم الرئيسية غير الابتدائية على أي حال. يسمح لك بمعالجة المفتاح الأساسي المركب كخاصية واحدة ، ويسمح بإعادة استخدام @Embeddable
الفصل في الجداول الأخرى.
النهج الأكثر طبيعية هو استخدام @EmbeddedId
بطاقة شعار. هنا ، لا يمكن استخدام فئة المفاتيح الأساسية في الجداول الأخرى لأنها ليست @Embeddable
الكيان ، لكنه يسمح لنا بمعالجة المفتاح كسمة واحدة لبعض الفئات.
أخيرًا ، استخدام @IdClass
و @Id
تتيح لنا التعليقات التوضيحية تعيين فئة المفاتيح الأساسية المركبة باستخدام خصائص الكيان نفسه المقابل لأسماء الخصائص في الفئة الرئيسية. يجب أن تتوافق الأسماء (لا توجد آلية لتجاوز هذا) ، ويجب أن يحترم الطبقة الرئيسية الأساسية نفس الالتزامات كما هو الحال مع التقنيتين الأخريين. الميزة الوحيدة لهذا النهج هي قدرتها على "إخفاء" استخدام فئة المفاتيح الأساسية من واجهة الكيان المرفق. ال @IdClass
يأخذ التعليق التوضيحي معلمة قيمة لنوع الفئة ، والتي يجب أن تكون الفئة المراد استخدامها كمفتاح أساسي مركب. يجب شرح الحقول التي تتوافق مع خصائص فئة المفاتيح الأساسية المراد استخدامها @Id
.
بقدر ما أعرف ما إذا كان PK المركب الخاص بك يحتوي @IdClass
مع @EmbeddedId
عليك تحديد رسم الخرائط لعمود FK الخاص بك مرتين ، Onece في @Embeddedable
ومرة واحدة مثل IE @ManyToOne
أين @ManyToOne
يجب أن تكون للقراءة فقط (@PrimaryKeyJoinColumn
) لأنه لا يمكن أن يكون لديك عمود واحد في متغيرين (صراعات محتملة).
لذلك عليك تعيين FK الخاص بك باستخدام نوع بسيط في @Embeddedable
.
على الموقع الآخر باستخدام @IdClass
يمكن التعامل مع هذا الموقف أسهل بكثير كما هو موضح في المفاتيح الأولية من خلال علاقات OneToOne و ManyToone:
مثال JPA 2.0 ManyToone معرف التعليق
...
@Entity
@IdClass(PhonePK.class)
public class Phone {
@Id
private String type;
@ManyToOne
@Id
@JoinColumn(name="OWNER_ID", referencedColumnName="EMP_ID")
private Employee owner;
...
}
مثال فئة jpa 2.0 معرف
...
public class PhonePK {
private String type;
private long owner;
public PhonePK() {}
public PhonePK(String type, long owner) {
this.type = type;
this.owner = owner;
}
public boolean equals(Object object) {
if (object instanceof PhonePK) {
PhonePK pk = (PhonePK)object;
return type.equals(pk.type) && owner == pk.owner;
} else {
return false;
}
}
public int hashCode() {
return type.hashCode() + owner;
}
}
أعتقد أن الميزة الرئيسية هي أنه يمكننا استخدام @GeneratedValue
للمعرف عند استخدام @IdClass
؟ أنا متأكد من أننا لا نستطيع استخدام @GeneratedValue
إلى عن على @EmbeddedId
.
يجب ألا يحتوي المفتاح المركب على @Id
الممتلكات متى @EmbeddedId
يستخدم.
مع تضمينك ، يمكنك استخدام البند في HQL ، على سبيل المثال: FROM Entity WHERE id IN :ids
عندما يكون المعرف عبارة FROM Entity WHERE idPartA = :idPartA0 AND idPartB = :idPartB0 .... OR idPartA = :idPartAN AND idPartB = :idPartBN