سؤال

لنفترض رسم خريطة مثل هذا

@Entity
public class User {

    private Integer id

    private List<Info> infoList;    

    @Id
    public getId() {
        return this.id;
    }

    @OneToMany(cascade=CascadeType.ALL)
    @JoinColumn(name="USER_ID", insertable=false, updateable=false, nullable=false)
    public getInfoList() {
        return this.infoList;
    }

    public void addQuestion(Info question) {
        info.setInfoCategory(InfoCategory.QUESTION);
        info.setInfoId(new InfoId(getId(), getInfoList().size()));

        getInfoList().add(question);
    }

    public void addAnswer(InfoRepository repository, Integer questionIndex, Info answer) {
        Info question = repository.getInfoById(new InfoId(getId(), questionIndex));

        if(question.getInfoCategory().equals(InfoCategory.ANSWER))
            throw new RuntimeException("Is not a question");

        if(question.getAnswer() != null)
            throw new RuntimeException("You can not post a new answer");

        answer.setInfoCategory(InfoCategory.ANSWER);
        answer.setInfoId(new InfoId(getId(), getInfoList().size()));

        getInfoList().add(answer);

        question.setAnswer(answer);
    }

}

وسؤال وجواب تم تعيينه بواسطة فئة المعلومات

@Entity
public class Info implements Serializable {

    private InfoId infoId;

    private Info answer;

    private InfoCategory infoCategory;

    public Info() {}

    @Embeddable
    public static class InfoId {

        private Integer userId;
        private Integer index;

        public InfoId(Integer userId, Integer index) {
            this.userId = userId;
            this.index = index;
        }

        @Column("USER_ID", updateable=false, nullable=false)
        public getUserId() {
            return this.userId;
        } 

        @Column("INFO_INDEX", updateable=false, nullable=false)
        public getIndex() {
            return this.index;
        }

        // equals and hashcode

    }

    // mapped as a ManyToOne instead of @OneToOne
    @ManyToOne
    JoinColumns({
        JoinColumn(name="USER_ID", referencedColumnName="USER_ID", insertable=false, updateable=false),
        JoinColumn(name="ANSWER_INDEX", referencedColumnName="INFO_INDEX", insertable=false)
    })
    public Info getAnswer() {
        return this.answer;  
    }

    @EmbeddedId
    public InfoId getInfoId() {
        return this.infoId;
    }

}

في getAnswer أستخدم ManyToOne بدلاً من OneToOne لأن بعض المشكلات المتعلقة بتعيين OneToOne.يمكن تعيين OneToOne على أنه ManyToOne (فريد = صحيح في @JoinColumn).INFO_INDEX لا يرتبط بأي غرض محدد.مجرد مفتاح لدعم المفتاح الأساسي المركب في نظام LEGACY.

قبل الإجابة احرص على ما يلي:

إذا كان للكائن معرف معين، أو مفتاح مركب، فيجب تعيين المعرف لمثيل الكائن قبل استدعاء save()

لذلك لا بد لي من رسم الخريطة JoinColumn(name = "USER_ID"، referencedColumnName = "USER_ID"، قابل للإدراج = خطأ، قابل للتحديث = خطأ) في getAnswer لأن Hibernate لا يسمح لخاصيتين قابلتين للتغيير بمشاركة نفس العمود (يستخدم معرف المستخدم أيضًا USER_ID) وإلا سأحصل على USER_ID في خاصية الإجابة التي يجب تعيينها باستخدام Insertable=false، Updateable=false

الآن نلقي نظرة على رسم الخرائط getAnswer

@ManyToOne
JoinColumns({
    JoinColumn(name="USER_ID", referencedColumnName="USER_ID", insertable=false, updateable=false),
    JoinColumn(name="ANSWER_INDEX", referencedColumnName="INFO_INDEX", insertable=false)
})

لأنه يشكو من عدم إمكانية مزج Hibernate بين العناصر القابلة للإدراج والتحديث

ماذا علي أن أفعل من أجل تمريرها؟

احرص على أنه نظام قديم.

يعتبر،

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

المحلول 2

ووفقا للمسألة في رسم الخرائط getAnswer

@ManyToOne
JoinColumns({
    JoinColumn(name="USER_ID", referencedColumnName="USER_ID", insertable=false, updateable=false),
    JoinColumn(name="ANSWER_INDEX", referencedColumnName="INFO_INDEX", insertable=false)
})

وسوف السبات الشكوى لأنه لا يسمح مزيج insertable مختلفة وقابلة للتحديث. لاحظت وجود insertable وتحديث في USER_ID JoinColumn وinsertable فقط في ANSWER_INDEX JoinColumn.

وذلك من أجل تمريرها، أقوم بإعداد ANSWER_INDEX JoinCollumn accortding إلى

JoinColumn(name="ANSWER_INDEX", referencedColumnName="INFO_INDEX", insertable=false, updateable=false)

وبهذه الطريقة، سوف السبات لا يشكو.

وأقوم بإعداد خاصية جديدة تسمى answerIndex

private Integer answerIndex;   

@Column(name="ANSWER_INDEX", insertable=false)
public void getAnswerIndex() {
    return this.answerIndex;
}

وبعد ذلك في addAnswer المستخدم

public void addAnswer(InfoRepository repository, Integer questionIndex, Info answer) {
    Info question = repository.getInfoById(new InfoId(getId(), questionIndex));

    if(question.getInfoCategory().equals(InfoCategory.ANSWER))
        throw new RuntimeException("Is not a question");

    if(question.getAnswer() != null)
        throw new RuntimeException("You can not post a new answer");

    answer.setInfoCategory(InfoCategory.ANSWER);
    answer.setInfoId(new InfoId(getId(), getInfoList().size()));

    getInfoList().add(answer);

    // Added in order to set up AnswerIndex property
    question.setAnswerIndex(answer.getInfoId().getIndex());
}

نصائح أخرى

انت ترغب بشكل جذري قم بتبسيط عملية التعيين الخاصة بك عن طريق التخلي عن المعرف المضمن واستخدام PK بديل بدلاً من ذلك.

إذا كنت بحاجة إلى استخدام InfoId.index لغرض ما (لطلب الأسئلة/الإجابات؟يمكنك تحديد ذلك في list رسم الخرائط)، احتفظ بها كملكية عادية.

UserId سيتم استبداله ManyToOne على User;نهاية الجمعية الأخرى (في User class) سيتم تعيينها كـ @OneToMany(mappedBy="User")

لماذا تم تعيين الإجابة على أنها ManyToOne؟لا ينبغي أن يكون OneToMany (على سبيل المثالسؤال واحد للعديد من الإجابات)؟في كلتا الحالتين، يعد تعيين الفصل على نفسه أقل من مثالي - فأنت تقوم بشكل أساسي بتنفيذ تسلسل هرمي لنموذج "قائمة مجاورة" وهو غير فعال؛بالإضافة إلى أنه في حالتك ستحتاج إلى التأكد من أنه لا يزيد عن مستويين.سأرسم خريطة Question و Answer كفئات منفصلة؛يمكنك جعلهم ينفذون واجهة مشتركة أو يوسعون نفس الفئة الأساسية (ربما مجردة)؛وفي كلتا الحالتين، ستتمكن من الاستمتاع بتعدد الأشكال الضمني الذي توفره لك لعبة Hibernate.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top