January 10, 2014

ORM : Composite Primary Keys

ယခင် တစ်ခေါက် ဖြင့် @ID Annotation အား အသုံးပြု၍ Primary Key တစ်ခုနှင့် Map လုပ်ပုံကို ဖော်ပြခဲ့၏။ သို့ရာတွင် Business လိုအပ်ချက်အရ Primary Key အား Composite Key Columns အနေနှင့် အသုံးပြုသည့်အခါလည်းရှိ၏။ ဥပမာအားဖြင့်၊ Date, Country Code ဒါမှမဟုတ် Currency Code များအား ပူးပေါင်း၍ အသုံးပြုသည့် အခါလည်းရှိမည်။ ထိုကဲ့သို့သော အခါများတွင် @EmbeddedId နှင့် @Id Annotation များအား အသုံးပြုနိုင်မည် ဖြစ်ပါသည်။ ၎င်းတို့မှာ ရေးသားအသုံးပြုပုံ ခြားနားသော်လည်း နောက်ဆုံး Database အတွင်း တည်ဆောက်သွားပုံမှာ အတူတူ ပင်ဖြစ်သည်။ တစ်ခုချင်း ရေးသား၍ စမ်းသပ်ကြည့်ပါဦးမည်။


Embedded Id

နောက်ပိုင်း အခန်းများတွင် ဖော်ပြသွားမည် ဖြစ်သော်လည်း Entity Class အတွင်းတွင် အခြားသော Object များအား Embedded အနေနှင့် အသုံးပြုနိုင်ပါသည်။ အဆိုပါ Embeddable Class များ၏ Properties များတွင် ID Key Column မပါဝင်ပဲ၊ Table ၏ Column များ အနေနှင့် ဖြည့်စွက် အသုံးပြုသွားနိုင်မည် ဖြစ်ပါသည်။

Composite Key အနေနှင့် အသုံးပြုလိုသည့်အခါ အဆိုပါ Embeddable Class အား Embedded Id အနေနှင့် အသုံးပြုနိုင်မည် ဖြစ်ပါသည်။ လက်တွေ့ ရေးသားကြည့်ပါမည်။

ဦးစွာ Embedded ID အနေနှင့် အသုံးပြုမည့် Embeddable Class အား ရေးသားပါမည်။
@Embeddable
public class ClassID implements Serializable {

    @Column(name="student_id")
    private int studentId;
    @Column(name="regist_date")
    @Temporal(TemporalType.DATE)
    private Date registDate;
    @Column(name="course_id")
    private int courseId;

    private static final long serialVersionUID = -6397573776691016968L;

    public ClassID() {}
    
    public ClassID(int studentId, Date date, int courseId) {
        this.studentId = studentId;
        this.registDate = date;
        this.courseId = courseId;
    }
    
    
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + courseId;
        result = prime * result
                + ((registDate == null) ? 0 : registDate.hashCode());
        result = prime * result + studentId;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        ClassID other = (ClassID) obj;
        if (courseId != other.courseId)
            return false;
        if (registDate == null) {
            if (other.registDate != null)
                return false;
        } else if (!registDate.equals(other.registDate))
            return false;
        if (studentId != other.studentId)
            return false;
        return true;
    }

    // getter and setter


အထက်ပါ ClassId Class ထဲတွင်  @Embeddable Annotation အား ဖြည့်စွက် ရေးသားရန် လိုအပ်ပြီး၊ ၎င်းအား အခြားသော Class အတွင်းမှ @Embedded အနေနှင့်၎င်း၊ @EmbeddedId အနေနှင့် သော်၎င်း အသုံးပြုနိုင်မည် ဖြစ်သည်။

Embeddable Class အား ရေးသားရာတွင် Id အား ရေးသားရန် မလိုအပ်ပဲ၊ Serializable Interface အား Implements လုပ်ရန် လိုအပ်ပြီး၊ hashCode နှင့် equals method တို့အား Override လုပ်၍ ရေးသားရန် လိုအပ်ပါသည်။ အဆိုပါ Method များအား Eclipse ၏ Generate Source Function အား အသုံးပြု၍ အလိုအလျှောက် ရေးသားနိုင်ပါသည်။
Member အနေနှင့် int studentId, Date registDate နှင့် int courseId တို့အား ရေးသားထားပါသည်။ Member Variable Name နှင့် Table Column Name အား ခွဲခြားအသုံးပြုနိုင်ရန် @Column Attribute အား အသုံးပြုထားပြီး၊ Date ပုံစံအား အသုံးပြုနိုင်ရန် အတွက် @Temporal Annotation အား အသုံးပြုထားပါသည်။ အဆိုပါ Annotation များနှင့် ပတ်သက်၍ နောက်အခန်းများတွင် အသေးစိတ်ဖော်ပြသွားပါမည်။
ပြီးပါက အထက်ပါ Embeddable Class အား Entity Class အတွင်း EmbeddedId အနေနှင့် အသုံးပြုနိုင်မည် ဖြစ်သည်။ အသုံးပြုပုံမှာ အောက်ပါအတိုင်း ဖြစ်ပါသည်။
@Entity
public class Class implements Serializable {

    @EmbeddedId
    private ClassID id;
    
    private boolean registered;
    private boolean finished;
    
    // constructor, getter and setter


အထက်ပါ Entity Class အား Test Class အတွင်းမှ ခေါ်၍ အသုံးပြုကြည့်ပါက အောက်ပါအတိုင်း CLASS Table အား တည်ဆောက်သွားမည် ဖြစ်သည်။
အထက်ဖော်ပြပါအတိုင်း Embeddable Class အတွင်းမှ Member များအားလုံးသည် Primary Key Columns များအနေနှင့် CLASS Table အတွင်း တည်ဆောက်သွားနိုင်သည်ကို တွေ့ရပါသည်။


ID Class


Composite Key အား ဖော်ပြနိုင်သော အခြားသောနည်းလမ်း တစ်ခုမှာ @IdClass ပင် ဖြစ်၏။ သာမန် POJO Class တစ်ခုအား Id Class အနေနှင့် အသုံးပြုခြင်း ဖြစ်၏။ ID Class အဖြစ်အသုံးပြုနိုင်ရန် အတွက် Class တစ်ခုမှာ Serializable Interface အား implements လုပ်ထားရန်လိုအပ်ပြီး၊ Java Beans Technology အား လိုက်နာ၍ ရေးသားရန် လိုအပ်ပါသည်။ ထို့အပြင် Argument မပါသော Constructor တစ်ခုလည်း မရှိမဖြစ်လိုအပ်ပြီး၊ hashCode နှင့် equals method တို့ကိုလည်း Override လုပ်ပြီး ရေးသားထားရပါမည်။

ဤသို့ဆိုလျှင် Embeddable Class နှင့် ဘာများကွာခြားသနည်းဟု မေးစရာရှိပါမည်။ အဖြေရှိပါသည်။ @Embeddable Annotation အား ရေးသားရန် မလိုအပ်ပဲ၊ Entity Class အတွင်းတွင် အသုံးပြုမည့် ID Properties များအား ရေးသားထားရန် လိုအပ်ပါသည်။

IdClass အား အသုံးပြုရသည်မှာ Id Class အတွင်းရှိ Properties များနှင့် တူညီသော Properties များအား မဖြစ်မနေ Entity Class အတွင်းတွင် ရေးသာရန် လိုအပ်သောကြောင့် မှားယွင်းလွယ်တတ်ပါသည်။ သို့ရာတွင် ရှိပြီးသား Class တစ်ခုအား ပြုပြင်ရန် မဖြစ်နိုင်သည့်အခါ Embeddable ထက်စာလျှင် IdClass အား ရွေးချယ်နိုင်မည် ဖြစ်သည်။ ထို့အပြင် JPQL ရေးသားရာ၌ Embeddable ထက်စာလျှင် ပိုလွယ်ပါသည်။

Embeddable အားအသုံးပြုပါက
select c from Class c where c.id.studentId = 1

IdClass အား အသုံးပြုထားပါက
select c from Class c where c.studentId = 1

ဆက်လက်၍ အထက်တွင်ရေးသားထားခဲ့သည့် Class Entity အား Id Class အားအသုံးပြု၍ ပြန်လည် ရေးသားကြည့်ပါဦးမည်။
public class ClassID implements Serializable{

    private int studentId;
    private Date registDate;
    private int courseId;
    
    // constructor, getter, setter, hashCode And equals

ပြီးပါက ၎င်း ID Class အားအသုံးပြုမည့် Entity Class အား ရေးသားပါမည်။
@Entity
@IdClass(ClassID.class)
public class Class implements Serializable {

    @Id
    @Column(name="student_id")
    private int studentId;
    @Id
    @Column(name="regist_date")
    @Temporal(TemporalType.DATE)
    private Date registDate;
    @Id
    @Column(name="course_id")
    private int courseId;

    private boolean registered;
    private boolean finished;
    
    // constructor, getter and setter
အထက်ဖော်ပြပါ အတိုင်း Class ၏ အပေါ်ဘက်တွင် @IdClass Annotation အား ရေးသားထားပြီး၊ ၎င်း၏တန်ဖိုးအဖြစ် Id Class ၏ Class အား ရေးသားထားပါသည်။ တဖန် Id Class အတွင်း ရေးသားထားသော Properties များအား Entity အတွင်းတွင် Type ရော Name ပါ တူညီအောင် ရေးသားထားရန် လိုအပ်ပါသည်။ ထို့အပြင် @Id Annotation အားလည်း ရေးသားရန် လိုအပ်ပါသည်။

အဆိုပါ Entity Class အား Test Class  အတွင်းမှ ခေါ်ယူ အသုံးပြုသောအခါ Database အတွင်းတွင် Embeddable တွင် အလုပ်လုပ်ထားသကဲ့သို့ Table အား တည်ဆောက်နိုင်မည် ဖြစ်ပါသည်။

ကျွှန်တော်တို့ Composite Key Columns များအား Embeddable နှင့် IdClass အား အသုံးပြု၍ ရေးသားခဲ့ပါသည်။ ရလဒ်မှာ အတူတူဖြစ်သော်လည်း အသုံးပြုပုံမှာ အနည်းငယ်ကွာခြားပါသည်။ EmbeddedId Object နှင့် Find လုပ်ရသည်မှာ လွယ်ကူပါသဖြင့် သာမန်အားဖြင့် EmbeddedId အားအသုံးပြုဖြစ်မည် ဖြစ်သော်လည်း၊ ရှိပြီးသား Legacy Class တစ်ခုအား ပြုပြင်၍မရပဲ Id အဖြစ် အသုံးပြုလိုသောအခါ IdClass အား အသုံးပြုသည်က သင့်တော်မည် ဖြစ်ပါသည်။

နောက်အခန်းများဖြင့် Column များအား Mapping လုပ်နည်းများအား ဆက်လက်လေ့လာ သွားပါဦးမည်။

လေးစားစွာဖြင့်
မင်းလွင် 

1 comment: