February 1, 2014

ORM : Relationships of Entities

Object Oriented Programming သည် Class များအား အသုံးပြုပြီး၊ Class များ၏ ပတ်သက်မှု့လည်း သတ်မှတ် အသုံးပြုနေပါသည်။ Class များ၏ ပတ်သက်မှု့သည် Object တစ်ခုနှင့်တစ်ခုအား ဖွဲ့စည်းပုံအရ ဆက်သွယ်ပေးနိုင်ပြီး၊ မိမိ၏ ပြောင်းလည်းမှု့သည်လည်း အခြားသော Object အား ပြောင်းလည်းမှု့ကို ပေးနိုင်သလို၊ အခြားသော Object ၏ ပြောင်းလည်းမှု့သည်လည်း မိမိတွင်အကျိုးသက်ရောက်မှု့ ရှိနိုင်ပါသည်။ Object များ၏ ပတ်သက်မှု့ ပုံစံ အမျိုးမျိုးရှိကြပါသည်။

OOP တွင် ပတ်သက်ပုံအား ဖော်ပြရာတွင် အခြေခံအားဖြင့် Is A Relation နှင့် Has A Relation ဟူ၍ နှစ်မျိုးနှစ်စား ခွဲခြားနိုင်ပါသည်။ တစ်ခုမှာ မိမိ၏ Object အတွင်းတွင် အခြားသော Object အား Member အဖြစ် ပိုင်ဆိုင်သောနည်းဖြစ်ပြီး ၎င်းအား Has A Relation ဟု ခေါ်ဆိုလေ့ရှိ၏။ Is A Relation အကြောင်းကိုမူ Inheritance Mapping အခန်းတွင် အသေးစိတ်ဖော်ပြမည် ဖြစ်သောကြောင့် ဤအခန်းတွင် ဖော်ပြတော့မည် မဟုတ်ပါ။

student.getAddress().getCountry() ဟု ရေးသားထားသည်ကို စဉ်းစားကြည့်ပါမည်။ Student Object ၏ Address အား getAddress method အား အသုံးပြု၍ခေါ်ယူပြီး၊ ၎င်းမှတဆင့် getCountry ဖြင့် Country Object အား ဆက်သွယ်နိုင်ပါသည်။ ဤအချက်ကိုကြည့်ခြင်းအားဖြင့် Object များတွင် ခေါ်ဆိုနိုင်သည့် Direction ရှိပြီး၊ သူ့အနေနှင့် တစ်ဘက်တည်းသော်၎င်း အပြန်အလှန်သော်၎င်း ရှိနိုင်ပါသည်။ UML ရေးသားနည်းတွင် Direction တစ်ဘက်တည်းရှိပါက ညွှန်ပြရာဘက်ကို မျှားညွှန်၍ ရေးသားရပြီး၊ အပြန်အလှန် ညွှန်းနေပါက မျှားအား ရေးသားရန် မလိုအပ်ပါ။

ပိုင်ဆိုင်ရာတွင်လည်း ထို Object အဖြစ်သော်၎င်း၊ Collection အဖြစ်သော်၎င်း ပိုင်ဆိုင်နိုင်ပါသည်။ Object တစ်ခုအတွင်းတွင် အခြားသော Object တစ်ခုအား Member အဖြစ်ပိုင်ဆိုင်သည်ဆိုပါအ တစ်ခုချင်းပတ်သက်သည်ဟု ဆိုနိုင်ပြီး၊ Collection ပုံစံနှင့် ပိုင်ဆိုင်သည် ဆိုပါက တစ်ခုနှင့် အများ ပတ်သက်သည်ဟု ဆိုနိုင်သည်။


Relational Database တွင် Table များ၏ ပတ်သက်ပုံအား OOP ကဲ့သို့ Collection များအား အသုံးပြု၍မရ ပေ။ Foreign Key များအားအသုံးပြု၍၎င်း၊ Join Table အား အသုံးပြု၍သော်၎င်း ဖော်ပြနိုင်ပါသည်။
အထက်ပါပုံတွင် Student ၏ Primary Key id အား Phone ၏ Foreign Key, Primary Key အနေနှင့် အသုံးပြု၍ Table များအား တစ်ခုခြင်း ပတ်သက်စေပါသည်။ တဖန် Student နှင့် Registration အား ကြည့်ပါက Student တစ်ခုနှင့် Registration အများအား ပတ်သက်စေပါသည်။ Registration နှင့် Course အားကြည့်ပါက Registration အများနှင့် Course တစ်ခုအား ပတ်သက်စေပါသည်။ နောက်ဆုံး Student နှင့် Course အား ကြည့်ပါက Registration အား Join Table အဖြစ်အသုံးပြုကာ အများနှင့် အများအနေနှင့် ပတ်သက်စေပါသည်။



One to One Relationship


Entity များအား တစ်ခုချင်း ပတ်သက်မှု့ရှိကြောင်းဖော်ပြလိုသည့် အခါ @OneToOne အား အသုံးပြုနိုင်ပါသည်။ Relation များတွင် Direction များအား အသုံးပြုနိုင်ပြီး၊ တစ်ဘက်တည်းသာ ဦးတည်ပါက Uni directional Relation ဟု ခေါ်ဆိုပြီ တစ်ဘက်တည်းမှသာ အခြား Entity အား ခေါ်ဆိုအသုံးပြုနိုင်မည် ဖြစ်ပါသည်။ မြင်လိုသည့် Entity အား ကြည့်လိုသည့် Entity အတွင်းတွင် ထည့်သွင်း ရေးသားရပါမည်။
UML အား အသုံးပြုပြီး ဖော်ပြမည် ဆိုပါက အထက်ပါအတိုင်း ကြည့်လိုသည့် Student မှ မြင်စေလိုသည့် Address ဘက်သို့ မျှားအား ဦးတည်၍ ရေးသားရပါသည်။

@Entity
public class Address implements Serializable {
       
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private long id;
    private String address;
        
    // serial number, getter and setter
}
@Entity
public class Student implements Serializable {
       
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private long id;
    private String name;
    
    @Temporal(TemporalType.DATE)
    private Date birthDate;
    
    @OneToOne(cascade = PERSIST)
    private Address address;
    
    // serial number, getter and setter
}
    
Student Entity နှင့် Address Entity တို့အား One To One ဖြင့် Map လုပ်ပြီး၊ Student အတွင်းမှ Address ကိုသာ ခေါ်ယူလိုသည့် အခါ Student အတွင်းတွင် Address အား Member အနေနှင့် ထည့်သွင်းပြီး @OneToOne အား ဖြည့်စွက် ရေးသားရပါသည်။

@OneToOne တွင် ရေးသားနိုင်သည့် Attribute များမှာ အောက်ပါအတိုင်း ဖြစ်ကြသည်။
အမည် အသုံးပြုပုံ
cascade Taret Entity အား ဆက်တိုက်လုပ်ဆောင်စေမည့် Operation များအား သတ်မှတ် ရေးသားနိုင်ပါသည်။ သတ်မှတ်ရေးသားထားသော Operation အား ပြုလုပ်ပါက Target Entity အားလည်း အလားတူ Operation ဖြင့် ဆက်တိုက်လုပ်ဆောင် သွားမည် ဖြစ်ပါသည်။ အသုံးပြုနိုင်သော Operation များမှာ အောက်ပါအတိုင်း ဖြစ်ကြ၏။
ALL, DETACH, MERGE, PERSIST, REFRESH, REMOVE
fetch fetch လုပ်မည့် အမျိုးအစားအား LAZY နှင့် EAGER အတွင်းမှ ရွေးချယ် နိုင်ပါသည်။
mapedBy Target Entity မှ Map လုပ်နေသည့် Member အား ရေးသားနိုင်ပါသည်။ ဤသို့ရေးသားထားပါက Foreign Key အား အခြားသော Entity ဘက်တွင် တည်ဆောက်သွားမည် ဖြစ်ပါသည်။
optional Default တန်ဖိုးမှာ true ဖြစ်ပြီး၊ Optional အနေနှင့် အသုံးပြုနိုင်ပုံအား သတ်မှတ်ရာတွင် ရေးသားရပါသည်။ အကယ်၍ false အား အသုံးပြုထားပါက Target Entity အား null တန်ဖိုးဖြင့် ရေးသားနိုင်မည် မဟုတ်ပါ။
orphanRemoval လက်ရှိ Entity အား Remove လုပ်ပါကာ ဆက်လက်၍ Target Entity အား Remove လုပ်လိုသည့်အခါ တန်ဖိုးအား true ဟု ဖြည့်စွက်ရေးသားနိုင်ပြီး Default တန်ဖိုးမှာ false ဖြစ်ပါသည်။
targetEntity ပတ်သက်နေသော Target Class အား ဖြည့်စွက် ရေးသားနိုင်ပါသည်။

အထက်ပါ Entity များအား စမ်းသပ်ကြည့်သောအခါ အောက်ပါအတိုင်း Table များအား တည်ဆောက်ပေးသွား ပါသည်။
CREATE TABLE STUDENT (
    ID BIGINT AUTO_INCREMENT NOT NULL, 
    BIRTHDATE DATE, 
    NAME VARCHAR(255), 
    ADDRESS_ID BIGINT, 
    PRIMARY KEY (ID))
CREATE TABLE ADDRESS (
    ID BIGINT AUTO_INCREMENT NOT NULL, 
    ADDRESS VARCHAR(255), 
    PRIMARY KEY (ID))
ALTER TABLE STUDENT 
    ADD CONSTRAINT 
        FK_STUDENT_ADDRESS_ID FOREIGN KEY (ADDRESS_ID) 
        REFERENCES ADDRESS (ID)
Student အထဲတွင် Address အား ထည့်သွင်းထားသောကြောင့် STUDENT TABLE အတွင်းတွင် ADDRESS_ID အမည်ဖြင့် ADDRESS ၏ ID အား Foreign Key အနေနှင့် တည်ဆောက်ပြီး ပတ်သက်မှု့အား ဖော်ပြနိုင်သည်ကို တွေ့ရပါသည်။
နှစ်ဘက်စလုံးမှ အသီးသီးမြင်စေလိုပါက Entity အသီးသီးတွင် အပြန်အလှန် Member အဖြစ် ထည့်သွင်း ရေးသားရန် လိုအပ်ပြီး၊ ၎င်းအား Bi Directional Relation ဟု ခေါ်ဆိုပါသည်။ UML ဖြင့်ရေးမည် ဆိုပါက မျှားအား ရေးသားရန် မလိုအပ်ပါ။


One to Many Relationship

အကယ်၍ ကျောင်းသားတစ်ဦးတွင် လိပ်စာအများအား ပိုင်ဆိုင်ကြောင်း ဖော်ပြလိုသည့်အခါ @OneToMany အား အသုံးပြုနိုင်ပါသည်။ Student Entity အတွင်းတွင် Address Entity အား List အနေနှင့် ဖြည့်စွက်ပြီး၊ @OneToMany Annotation အား ရေးသား၍ အသုံးပြုနိုင်ပါသည်။

public class Student implements Serializable {

       
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private long id;
    private String name;
    
    @Temporal(TemporalType.DATE)
    private Date birthDate;

    @OneToMany(cascade = ALL)
    private List<Address> addresses;
    
    // serial number, getter and setter
}
အထက်ပါအတိုင်း Student Entity အတွင်းတွင် Address များအား List အနေနှင့် ဖြည့်စွက်ထားပါက One To Many အနေနှင့် Map လုပ်နိုင်မည် ဖြစ်ပါသည်။ @OneToMany တွင် ရေးသားနိုင်သော Attribute များမှာ အောက်ပါအတိုင်း ဖြစ်ကြသည်။
အမည် အသုံးပြုပုံ
cascade Taret Entity အား ဆက်တိုက်လုပ်ဆောင်စေမည့် Operation များအား သတ်မှတ် ရေးသားနိုင်ပါသည်။ သတ်မှတ်ရေးသားထားသော Operation အား ပြုလုပ်ပါက Target Entity အားလည်း အလားတူ Operation ဖြင့် ဆက်တိုက်လုပ်ဆောင် သွားမည် ဖြစ်ပါသည်။ အသုံးပြုနိုင်သော Operation များမှာ အောက်ပါအတိုင်း ဖြစ်ကြ၏။
ALL, DETACH, MERGE, PERSIST, REFRESH, REMOVE
fetch fetch လုပ်မည့် အမျိုးအစားအား LAZY နှင့် EAGER အတွင်းမှ ရွေးချယ် နိုင်ပါသည်။
mapedBy Target Entity မှ Map လုပ်နေသည့် Member အား ရေးသားနိုင်ပါသည်။ ဤသို့ရေးသားထားပါက Foreign Key အား အခြားသော Entity ဘက်တွင် တည်ဆောက်သွားမည် ဖြစ်ပါသည်။
orphanRemoval လက်ရှိ Entity အား Remove လုပ်ပါကာ ဆက်လက်၍ Target Entity အား Remove လုပ်လိုသည့်အခါ တန်ဖိုးအား true ဟု ဖြည့်စွက်ရေးသားနိုင်ပြီး Default တန်ဖိုးမှာ false ဖြစ်ပါသည်။
targetEntity ပတ်သက်နေသော Target Class အား ဖြည့်စွက် ရေးသားနိုင်ပါသည်။
အထက်ပါ Entity များအား စမ်းသပ်ကြည့်သောအခါ အောက်ပါအတိုင်း Table များအား တည်ဆောက်ပေးသွားနိုင်သည်ကို တွေ့ရပါသည်။
CREATE TABLE STUDENT 
    (ID BIGINT AUTO_INCREMENT NOT NULL, 
    BIRTHDATE DATE, NAME VARCHAR(255), 
    PRIMARY KEY (ID))
CREATE TABLE ADDRESS 
    (ID BIGINT AUTO_INCREMENT NOT NULL, 
    ADDRESS VARCHAR(255), 
    PRIMARY KEY (ID))
CREATE TABLE STUDENT_ADDRESS 
    (student_id BIGINT NOT NULL, 
    addresses_ID BIGINT NOT NULL, 
    PRIMARY KEY (student_id, addresses_ID))
ALTER TABLE STUDENT_ADDRESS 
    ADD CONSTRAINT 
    FK_STUDENT_ADDRESS_addresses_ID 
    FOREIGN KEY (addresses_ID) 
    REFERENCES ADDRESS (ID)
ALTER TABLE STUDENT_ADDRESS 
    ADD CONSTRAINT FK_STUDENT_ADDRESS_student_id 
    FOREIGN KEY (student_id) 
    REFERENCES STUDENT (ID)
အထက်ပါအတိုင်း STUDENT နှင့် ADDRESS အား STUDENT_ADDRESS ဖြင့် ချိတ်ဆက်ပေးနိုင်သည်ကို တွေ့ရှိရပါသည်။


Many to One Relationship

အထက်တွင် ဖော်ပြခဲ့သော Student နှင့် Address တို့ဝင် Student ဘက်မှကြည့်ပါက One To Many ဖြစ်သော်လည်း Address ဘက်ကကြည့်မည်ဆိုပါက Many To One ပတ်သက်မှု့ ဖြစ်ပါသည်။ Many To One ပတ်သက်မှု့အား @ManyToOne အား အသုံးပြု၍ ရေးသားနိုင်ပါသည်။

တဖန် အထက်တွင် ဖော်ပြခဲ့သော One To Many တွင် STUDENT_ADDRESS အား Join Table အနေနှင့် တည်ဆောက်ကာ Map လုပ်ခဲ့ပါသည်။ Join Table အား အသုံးမပြုလိုဘူးဆိုပါက နှစ်ဘက်စလုံးတွင် Mapping အား ရေးသားပြီး၊ Many ဘက်က Attribute တွင် mapedBy ၏ တန်ဖိုးအား သတ်မှတ်ရေးသားနိုင်ပါသည်။
@Entity
public class Address implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private long id;
    private String address;
    @ManyToOne
    private Student student;
    
    // serial number, getter and setter
}
@Entity
public class Student implements Serializable {
       
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private long id;
    private String name;
    
    @Temporal(TemporalType.DATE)
    private Date birthDate;

    @OneToMany(cascade = ALL, mappedBy = "student")
    private List<Address> addresses;
    
    // serial number, getter and setter
}
@ManyToOne တွင် အသုံးပြုနိုင်သော Attrubute များမှာ အောက်ပါအတိုင်း ဖြစ်ကြပါသည်။
အမည် အသုံးပြုပုံ
cascade Taret Entity အား ဆက်တိုက်လုပ်ဆောင်စေမည့် Operation များအား သတ်မှတ် ရေးသားနိုင်ပါသည်။ သတ်မှတ်ရေးသားထားသော Operation အား ပြုလုပ်ပါက Target Entity အားလည်း အလားတူ Operation ဖြင့် ဆက်တိုက်လုပ်ဆောင် သွားမည် ဖြစ်ပါသည်။ အသုံးပြုနိုင်သော Operation များမှာ အောက်ပါအတိုင်း ဖြစ်ကြ၏။
ALL, DETACH, MERGE, PERSIST, REFRESH, REMOVE
fetch fetch လုပ်မည့် အမျိုးအစားအား LAZY နှင့် EAGER အတွင်းမှ ရွေးချယ် နိုင်ပါသည်။
optional Default တန်ဖိုးမှာ true ဖြစ်ပြီး၊ Optional အနေနှင့် အသုံးပြုနိုင်ပုံအား သတ်မှတ်ရာတွင် ရေးသားရပါသည်။ အကယ်၍ false အား အသုံးပြုထားပါက Target Entity အား null တန်ဖိုးဖြင့် ရေးသားနိုင်မည် မဟုတ်ပါ။
targetEntity ပတ်သက်နေသော Target Class အား ဖြည့်စွက် ရေးသားနိုင်ပါသည်။
အထက်ပါ ပရိုဂရမ်များအား အသုံးပြု၍ DDL အား Generate လုပ်သောအခါ အောက်ပါအတိုင်း ရရှိပါသည်။
CREATE TABLE STUDENT 
 (ID BIGINT AUTO_INCREMENT NOT NULL, 
 BIRTHDATE DATE, 
 NAME VARCHAR(255), 
 PRIMARY KEY (ID))
CREATE TABLE ADDRESS 
 (ID BIGINT AUTO_INCREMENT NOT NULL, 
 ADDRESS VARCHAR(255), 
 STUDENT_ID BIGINT, 
 PRIMARY KEY (ID))
ALTER TABLE ADDRESS 
 ADD CONSTRAINT FK_ADDRESS_STUDENT_ID 
 FOREIGN KEY (STUDENT_ID) 
 REFERENCES STUDENT (ID)

Student ၏ @ManyToOne တွင် mapedBy Attribute အား အသုံးပြုထားသောကြောင့် Join Table အား အသုံးမပြုပဲ၊ Foreign Key အား အသုံးပြုကာ ချိတ်ဆက်ပေးနိုင်ကြောင်းကို တွေ့ရမည် ဖြစ်ပါသည်။ မိမိက အသုံးပြုလိုသော DB ပုံစံအား စဉ်းစား၍ Mapping Annotation အား Customize လုပ်၍ ရေးသားသွားရန် လိုအပ်ပါသည်။


Many to Many Relationship

Student နှင့် Class တို့၏ ပတ်သက်မှု့အား စဉ်းစားကြည့်ပါမည်။ Class တစ်ခုအတွင်းတွင် Student အများပါဝင် တက်ရောက်နိုင်သလို၊ Student တစ်ယောက်သည်လည်း Class အများအပြားအား တက်ရောက်နိုင်သည့် အနေအထားမျိုးရှိမည် ဖြစ်ပါသည်။ ထိုအခါမျိုးတွင် Class အများနှင့် Student အများတို့သည် ပတ်သက်နေပြီး၊ ၎င်းအား Many To Many Relationship ဟု ခေါ်ဆိုပါသည်။ Relational Database တွင် အဆိုပါအခြေအနေမျိုးအား ကြားထဲတွင် Table တစ်ခုအားခံကာ ဖော်ပြပေးလေ့ရှိ၏။ JPA တွင်လည်း @ManyToMany အားအသုံးပြု၍ ရေးသားနိုင်ပါသည်။

@ManyToMany တွင် အသုံးပြုနိုင်သော Attribute များမှာ @ManyToOne တွင် အသုံးပြုခဲ့သော Attribute များ အတိုင်းပင် ဖြစ်ပါသည်။
@@Entity
public class Student implements Serializable {
       
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private long id;
    private String name;
    
    @Temporal(TemporalType.DATE)
    private Date birthDate;

    @ManyToMany
    @JoinTable(joinColumns = @JoinColumn(name = "STUDENT", 
        referencedColumnName = "id"), 
    inverseJoinColumns = @JoinColumn(name = "CLASS", 
        referencedColumnName = "id"))
    private List<Class> classes;
    
    // constructors, serial number, getter setter
}
@ManyToMany Annotation အားအသုံးပြုပါက Entity Class နှစ်ခုအား Join Table အား အသုံးပြု၍ ချိတ်ဆက်ပေးမည် ဖြစ်ပါသည်။ Default အတိုင်းဆိုပါက ပင်မ Entity ၏ အမည်နှင့် Target Entity ၏ အမည်အား Underscore ခံ၍ Join Table ၏ အမည်အား အသုံးပြုမည် ဖြစ်သည်။
@Entity
public class Class implements Serializable {

    @Id
    private long id;
    private String name;
    @ManyToMany
    @JoinTable(name = "STUDENT_CLASS", 
    joinColumns = @JoinColumn(name = "CLASS", 
        referencedColumnName = "id"), 
    inverseJoinColumns = @JoinColumn(name = "STUDENT", 
        referencedColumnName = "id"))
    private List<Student> students;
    
    // constructors, serial number, getter setter
}
အကယ်၍ Class Entity အတွင်းတွင်လည်း @ManyToMany အား ရေးသားထား၍၊ Default အတိုင်း ထားပါက STUDENT_CLASS နှင့် CLASS_STUDENT Join Table နှစ်ခုအား တည်ဆောက်သွားပါလိမ့်မည်။ ထို့ကြောင့် Class Entity တွင် @JoinTable Annotation အား အသုံးပြု ရေးသားကာ ၎င်း၏အမည်အား STUDENT_CLASS ဟု ရေးသား၍ STUDENT_CLASS တစ်ခုတည်းကိုသာ ရေးသားစေပါသည်။
အထက်ပါ Entity များအား အသုံးပြု၍ DDL အား Generate လုပ်သောအခါ အထက်ပါအတိုင်း STUDENT_CLASS Join Table အား အသုံးပြု၍ STUDENT နှင့် CLASS တို့အား Many To Many ဖြင့် ချိတ်ဆက်ပေးနိုင်သည်ကို တွေ့ရပါသည်။

ဆက်ပါဦးမည်။ လေးစားစွာဖြင့်။
မင်းလွင်

3 comments:

  1. At this time it looks like Expression Engine is the best blogging platform available right now.
    (from what I've read) Is that what you are using on your blog?

    ReplyDelete
  2. Excellent post. I was checking constantly this weblog and I am
    inspired! Very useful information particularly the remaining phase :) I deal with such info a
    lot. I was seeking this particular information for a very long time.

    Thank you and best of luck.

    ReplyDelete
  3. Wow, incredible blog layout! How long have you been blogging for?
    you make blogging look easy. The overall look of your site is great,
    let alone the content!

    ReplyDelete