هل يجب أن يكون Hibernate قادرًا على التعامل مع المفاتيح الخارجية المتداخلة؟

StackOverflow https://stackoverflow.com/questions/4231452

سؤال

لدي طاولة بها مفتاحين أجنبيين لجدولين مختلفين مع كل من المفاتيح الأجنبية مشاركة عمود واحد:

CREATE TABLE ZipAreas
(
  country_code CHAR(2) NOT NULL,
  zip_code VARCHAR(10) NOT NULL,
  state_code VARCHAR(5) NOT NULL,
  city_name VARCHAR(100) NOT NULL,
  PRIMARY KEY (country_code, zip_code, state_code, city_name),
  FOREIGN KEY (country_code, zip_code) REFERENCES Zips (country_code, code),
  FOREIGN KEY (country_code, state_code, city_name) REFERENCES Cities (country_code, state_code, name)
)

كما ترون ، هناك نوعان من FKS مشاركة Country_Code (يشيرون إلى حد ما في نفس العمود في نهاية مسار الإحالة). تبدو فئة الكيان مثل (JPA 1.0 IdClass):

@Entity
@Table(name = "ZipAreas")
@IdClass(value = ZipAreaId.class)
public class ZipArea implements Serializable
{
    @Id
    @Column(name = "country_code", insertable = false, updatable = false)
    private String countryCode;

    @Id
    @Column(name = "zip_code", insertable = false, updatable = false)
    private String zipCode;

    @Id
    @Column(name = "state_code", insertable = false, updatable = false)
    private String stateCode;

    @Id
    @Column(name = "city_name", insertable = false, updatable = false)
    private String cityName;

    @ManyToOne
    @JoinColumns(value = {@JoinColumn(name = "country_code", referencedColumnName = "country_code"), @JoinColumn(name = "zip_code", referencedColumnName = "code")})
    private Zip zip = null;

    @ManyToOne
    @JoinColumns(value = {@JoinColumn(name = "country_code", referencedColumnName = "country_code", insertable = false, updatable = false), @JoinColumn(name = "state_code", referencedColumnName = "state_code"), @JoinColumn(name = "city_name", referencedColumnName = "name")})
    private City city = null;

    ...
}

كما ترون ، قمت بالإبلاغ عن خاصية CountryCode و Country_Code @joincolumn كقراءة فقط (insertable = false ، updatable = false). فشل السبات في هذا القول:

Exception in thread "main" javax.persistence.PersistenceException: [PersistenceUnit: geoinfo] Unable to configure EntityManagerFactory
    at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:374)
    at org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:56)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:48)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:32)
    at tld.geoinfo.Main.main(Main.java:27)
Caused by: org.hibernate.AnnotationException: Mixing insertable and non insertable columns in a property is not allowed: tld.geoinfo.model.ZipAreacity
    at org.hibernate.cfg.Ejb3Column.checkPropertyConsistency(Ejb3Column.java:563)
    at org.hibernate.cfg.AnnotationBinder.bindManyToOne(AnnotationBinder.java:2703)
    at org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:1600)
    at org.hibernate.cfg.AnnotationBinder.processIdPropertiesIfNotAlready(AnnotationBinder.java:796)
    at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:707)
    at org.hibernate.cfg.Configuration$MetadataSourceQueue.processAnnotatedClassesQueue(Configuration.java:3977)
    at org.hibernate.cfg.Configuration$MetadataSourceQueue.processMetadata(Configuration.java:3931)
    at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1368)
    at org.hibernate.cfg.Configuration.buildMappings(Configuration.java:1345)
    at org.hibernate.ejb.Ejb3Configuration.buildMappings(Ejb3Configuration.java:1477)
    at org.hibernate.ejb.EventListenerConfigurator.configure(EventListenerConfigurator.java:193)
    at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:1096)
    at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:278)
    at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:362)
    ... 4 more

هذا يبدو أساسيا جدا بالنسبة لي بصراحة. "خلط الأعمدة القابلة للإدخال وغير القابلة للإدخال في خاصية غير مسموح بها" مثل هذا "عذر" ضعيف ، أليس كذلك؟

هل يجب أن يكون Hibernate قادرًا على التعامل مع هذا ، على سبيل المثال وفقًا لمواصفات JPA؟ هذا الخلل؟

هل كانت مفيدة؟

المحلول 2

سيتم دعمه مع Hibernate 5 ، انظر https://hibernate.atlassian.net/browse/hhh-6221

نصائح أخرى

هناك طريقة لتجاوز التحقق من الصحة وجعله يعمل ، وبالتالي تشير إلى أن العمود هو "joincolumnsorformulas" ثم ضع الحل:

خطأ:

@ManyToOne
@JoinColumns(value = {
    @JoinColumn(name = "country_code", referencedColumnName = "country_code"), 
    @JoinColumn(name = "zip_code", referencedColumnName = "code")})
private Zip zip = null;

@ManyToOne
@JoinColumns(value = {
    @JoinColumn(name = "country_code", referencedColumnName = "country_code", insertable = false, updatable = false),
    @JoinColumn(name = "state_code", referencedColumnName = "state_code"), 
    @JoinColumn(name = "city_name", referencedColumnName = "name")})
private City city = null;

نعم:

@ManyToOne
@JoinColumns(value = {
    @JoinColumn(name = "country_code", referencedColumnName = "country_code"), 
    @JoinColumn(name = "zip_code", referencedColumnName = "code")})
private Zip zip = null;

@ManyToOne
@JoinColumnsOrFormulas(value = {
    @JoinColumnOrFormula(formula = @JoinFormula(value = "country_code", referencedColumnName = "country_code")),
    @JoinColumnOrFormula(column = @JoinColumn(name = "state_code", referencedColumnName = "state_code")),
    @JoinColumnOrFormula(column = @JoinColumn(name = "city_name", referencedColumnName = "name"))
})
private City city = null;

يعتبر،

أنا أستخدم Hibernate 5 وما زلت أحصل على هذا الاستثناء. إذا قمت بإضافة insert = "false" ، update = "false" إلى واحد فقط ، فستحصل على استثناء يفيد بأنك مختلط من الأعمدة القابلة للإدراج وغير القابلة للإعلان وأن هذا غير مسموح به. هذه مشكلة موجودة بالفعل في المتتبع ، ولكن يبدو أنها لم يتم حلها. يرمي السبات التعليق التوضيحي على العمود المستخدمة من قبل العديد من المفاتيح الخارجية المتداخلة

في حالتنا ، هذا يعني أننا انتقلنا إلى Eclipselink ، وهو في الواقع سهل للغاية بالنظر إلى أنك تحتاج بشكل أساسي إلى استبدال المثابرة. xml وإعادة كتابة HSQL (Hibernate SQL) إلى JPQL (JPA SQL). قد تحتاج أيضًا إلى استبدال استراتيجيات التسمية المخصصة (يطلق عليها Eclipse SessionCustomizer). بالطبع ، قد يكون من الصعب القيام به إذا كنت تستخدم ميزات خاصة من السبات مثل البحث عن السبات وما إلى ذلك. ولكن في حالتنا ، حاولنا إصلاح المفاتيح الأجنبية المتداخلة لأسابيع عندما استغرقت الترحيل ساعات فقط في النهاية.

لا يزال هذا لم يتم حله في السبات 5. ومع ذلك ، إذا استخدمت @JoinColumnsOrFormulas أحصل على classcastexception. إلحاق insertable = false, updatable = false على جميع أعمدة الانضمام حل مشكلتي:

مثال:

@ManyToOne
@JoinColumns(value = {
    @JoinColumn(name = "country_code", referencedColumnName = "country_code", insertable = false, updatable = false),
    @JoinColumn(name = "state_code", referencedColumnName = "state_code", insertable = false, updatable = false), 
    @JoinColumn(name = "city_name", referencedColumnName = "name", insertable = false, updatable = false)})
private City city = null;
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top