جاوا و تکنولوژی های آن

java programming language

در این وبلاگ به بررسی نکات موجود در جاوا و تکنولوژی های آن می پردازیم

طبقه بندی موضوعی


معمولا هر Entity به یک Table از دیتابیس مرتبط است ولی گاهی نیاز به طراحی Entity ای داریم که به چند Table مرتبط است که در این بخش به بررسی و شرایط مورد نیاز آن می پردازیم 


شرایط خاص که یک Entity به چند Table تناظر خواهد داشت :


- وقتی یک گروه منطقی و تکرار شونده از فیلد ها در چند Table داریم و میخواهیم آن گروه از فیلد ها را در قالب یک Entity جداگانه دریافت کنیم

- وقتی که مسئله ارث بری مطرح باشد و جدول ما دارای یک سلسله مراتب ارث بری باشد و فیلد های مشترکی به ارث برده میشوند

- وقتی فیلد های مرتبط بهم در چند Table پخش باشند و ما میخواهیم آن فیلد ها را در قالب یک Entity داشته باشیم 




طراحی دیتا مدل :


فرض کنید میخواهیم شرایط یک رستوران را مدل کنیم و دیتای هر غذایی که سرو میشود را ذخیره کنیم مانند :


- name 

- description

- price

- what kind of allergens it contains (چه مواد آلرژی زایی در آن وجود دارد)


از آنجایی که موارد آلرژی زای زیادی برای هر غذا وجود دارد ما میتوانیم آنها را گروه بندی کنیم و جداول زیر را برای آن طراجی میکنیم :





ساخت Entity ها :


معمول ترین راه طراحی ایجاد یک Entity برای هر دو جدول است 


ابتدا Meal Entity را طراحی میکنیم :

@Entity
@Table(name = "meal")
class Meal {
 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    Long id;
 
    @Column(name = "name")
    String name;
 
    @Column(name = "description")
    String description;
 
    @Column(name = "price")
    BigDecimal price;
 
    @OneToOne(mappedBy = "meal")
    Allergens allergens;
 
    // standard getters and setters
}


سپس Allergens Entity :


@Entity
@Table(name = "allergens")
class Allergens {
 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "meal_id")
    Long mealId;
 
    @OneToOne
    @PrimaryKeyJoinColumn(name = "meal_id")
    Meal meal;
 
    @Column(name = "peanuts")
    boolean peanuts;
 
    @Column(name = "celery")
    boolean celery;
 
    @Column(name = "sesame_seeds")
    boolean sesameSeeds;
 
    // standard getters and setters
}


همانطور که در کد بالا میبینیم meal_id هم Primary key است و هم Foreign key که به معنای آن است که رابطه one-to-one بر قرار است و از PrimaryKeyJoinColumn@ استفاده کردیم 


این طراحی دو مشکل دارد :


- ما همیشه میخواهیم آلرژی ها را برای هر غذا ذخیره کنیم و این طراحی ما را ملزم نمیکند

- منطقا داده های آلرژی و غذا بهم تعلق دارند و میخواهیم این داده ها را در یک کلاس داشته باشیم حتی اگر برای ذخیره دیتای آنها چند جدول داشته باشیم 


برای مشکل اول راه حل استفاده از NotNull@ برای فیلد allergens در کلاس Meal است و اگر مقدار allergens برابر Null بود JPA اجازه ذخیره شدن را نمیدهد به هر حال این راه حل ایده آلی نیست و ما میخواهیم محدودیت بهتری اعمال کنیم تا جایی که اصلا امکان ذخیره Meal بدون Allergens نباشد 





ساخت یک Entity و استفاده از SecondaryTable@ :


ما میتوانیم یک کلاس Entity برای دو جدول مورد نظر بسازیم که فیلد های مربوط به جدول دوم آن با SecondaryTable@ مشخص شده باشد :


@Entity
@Table(name = "meal")
@SecondaryTable(name = "allergens", pkJoinColumns = @PrimaryKeyJoinColumn(name = "meal_id"))
class Meal {
 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    Long id;
 
    @Column(name = "name")
    String name;
 
    @Column(name = "description")
    String description;
 
    @Column(name = "price")
    BigDecimal price;
 
    @Column(name = "peanuts", table = "allergens")
    boolean peanuts;
 
    @Column(name = "celery", table = "allergens")
    boolean celery;
 
    @Column(name = "sesame_seeds", table = "allergens")
    boolean sesameSeeds;
 
    // standard getters and setters
 
}


در پشت صحنه Jpa برای این دو جدول Join خواهد زد این راه حل شبیه استفاده از OneToOne@ است ولی در این راه حل ما کلیه فیلد ها را در یک کلاس خواهیم داشت 


* باید توجه کنیم که اگر Column ما متعلق به جدول دوم باشد انرا با آرگومان table در Column@ مشخص میکنیم و اگر مربوط به جدول اصلی و اول باشد میتوانیم این آرگومان را ننویسیم و JPA اتوماتیک آنرا به عنوان جدول اصلی در نظر میگیرد


* همچنین میتونیم چندین جدول ثانویه داشته باشیم که در SecondaryTables@ بصورت embed قابل تعریف است ولی در جاوا 8 میتوانیم چند بار از SecondaryTables@ استفاده کنیم 





ترکیب SecondaryTables@ و Embedded@ :


همانطور که دیدیم با SecondaryTables@ توانستیم تناظر بین چند جدول را در یک Entity برقرار کنیم و از طرفی میدانیم که Embedded@ و Embeddable@ میتوانند برعکس کار کنند و یک جدول را به چند کلاس اختصاص دهند 


حال اگر ویژگی های انها را باهم ترکیب کنیم چه کمکی به طراحی ما خواهد کرد ؟ :

@Entity
@Table(name = "meal")
@SecondaryTable(name = "allergens", pkJoinColumns = @PrimaryKeyJoinColumn(name = "meal_id"))
class Meal {
 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    Long id;
 
    @Column(name = "name")
    String name;
 
    @Column(name = "description")
    String description;
 
    @Column(name = "price")
    BigDecimal price;
 
    @Embedded
    Allergens allergens;
 
    // standard getters and setters
 
}
 
@Embeddable
class Allergens {
 
    @Column(name = "peanuts", table = "allergens")
    boolean peanuts;
 
    @Column(name = "celery", table = "allergens")
    boolean celery;
 
    @Column(name = "sesame_seeds", table = "allergens")
    boolean sesameSeeds;
 
    // standard getters and setters
 
}


این طراحی مشابه حالتی است که با OneToOne@ پیاده سازی شده بود اما دو مزیت دارد :


JPA هر دو جدول را مدیریت میکند و میتوانیم مطمئن شویم که برای هر Meal در هر دو جدول یک Row وجود خواهد داشت و کد تمیزتر و کانفیگ کمتری نیاز دارد با این وجود این راه حل مشابه one to one زمانی درست کار خواهد کرد که Id های یکسان داشته باشد 


شایان ذکر است اگر ما بخواهیم از کلاس Allergens استفاده دیگری کنیم بهتر است Column های جدول دوم را در کلاس Meal همراه با AttributeOverride@ تعریف کنیم 










نظرات  (۱)

۰۸ بهمن ۹۹ ، ۰۰:۵۱ مهدی میرحسینی

مطلب خیلی مفیدی بود دستتون درد نکنه 

ارسال نظر

ارسال نظر آزاد است، اما اگر قبلا در بیان ثبت نام کرده اید می توانید ابتدا وارد شوید.
شما میتوانید از این تگهای html استفاده کنید:
<b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">
تجدید کد امنیتی