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

java programming language

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

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


Annotation های Hibernate : 



Entity : کلاس مدل را مشخص میکند و میتوان یک name هم بگیرد و اگر name بدهیم باید در HQL ها از آن نام استفاده کنیم که مرسوم نیست


Table : نام جدول متناظر با مدل فوق را مشخص میکند و اگر نگذاریم نام کلاس را پیش فرض به عنوان نام جدول در نظر میگیرد و name نام جدول موجود در دیتابیس را مشخص میکند و schema نام دیتابیس را مشخص میکند ، اگر برنامه ای داریم که multi schema است و ما به آن چند schema اعتبار کوئری زدن روی هم را داده باشیم باید نام schema را روی کلاس مدل حتما ذکر کنیم تا بتواند کار کند ، بعضی دیتابیس ها catalog هم دارند که خود در بر گیرنده چندین schema است و همانطور که میدانیم هر schema هم میتواند در بر گیرنده چندین table باشد و اگر catalog داشتیم انرا هم مشخص میکنیم  

با پراپرتی indexes مشخص میکنیم که چه index هایی برای کدام فیلد در دیتابیس بوجود بیایند و کاربردش برای موقع ساخت دیتابیس توسط هایبرنیت است ، که داخل indexes با استفاده از Index@ دو sub-property بنام name برای نام index و columnList برای نام فیلد هایی که قرار است از index استفاده کنند مشخص میکنیم 

و پراپرتی uniqueConstraints برای فیلد هایی که باید بصورت unique بتنهایی یا چند تایی یونیک باشند تعیین میشود و برای زمان DDL و ساخت دیتابیس استفاده میشود


Access : میتوان مشخص کرد که تعاریف فیلد ها از روی field name ها باشد و یا از طریق property ها (getter methods) و اگر نگذاریم هر دو را در نظر میگیرد


Column : نام فیلد ها را با نام column ها متناظر میکند و دارای پراپرتی هایی است :


با name نام ستون را با فیلد مشخص میکند و اگر name  نزاریم از اسم فیلد نام ستون را تعیین میکند البته میتوان با naming strategy نحوه تعیین نام ها را مشخص کرد که از چه الگویی باید تبعیت کند که بعدا بهش میپردازیم   ، پراپرتی length در مورد دیتا تایپ های رشته ای مشخص میکند که طول آن چقدر است و اگر مشخص نکنیم بصورت پیش فرض varchar 256 در نظر میگیرد 


 precision در مورد دیتا تایپ های عددی طول آن را مشخص میکند و اگر دیتا تایپ از نوع اعشاری بود میتوان علاوه بر precision که طول کلی عدد را مشخص میکند با scale تعداد رقم اعشار آنرا مشخص کنیم 

@Entity
@Table( name= "PERSON" schema = "schema1")
public class Person {

            @Column( name = "PERSON_ID" , precision = 15 , scal = 5 )
            private Double personId;
}

در اینجا یک عدد با طول 15 تعیین کردیم که 5 رقمش اعشار و 10 رقم صحیح دارد 


nullable مشخص میکند این فیلد نباید نال باشد و همیشه توسط هایبرنیت چک میشود و موقع ساخت جدول هم استفاده میشود اگر مشخص نکنیم بطور پیش فرض nullbale = true است 


 insertable = false مشخص میکند که هنگام insert شدن در پایگاه داده این فیلد نیازی نیست که insert شود و نادیده گرفته میشود مثلا زمانی کاربرد دارد که ما برای این فیلد در پایگاه داده trigger نوشته باشیم و توسط trigger آنرا پر کنیم  


updatable = false بعد از insert اولیه در update های بعدی روی این فیلد اعمال نمیشود و همان مقدار اولیه باقی میماند 


** نکته : میتوانیم در کلاس های entity دو فیلد را به یک نام ستون مپ کنیم ولی هایبرنیت به این شرط اینکار را میکند که یکی از آنها اصلی باشد و بقیه باید udatable = false , insertable = false باشد 

@Entity
@Table( name= "PERSON" schema = "schema1")
public class Person {

            @Column( name = "PERSON_ID")
            private Long personId;

            @Column( name = "PERSON_ID" , insertable = false , updatable = false )
            private Long personId2;
}


Transient : وقتی فیلدی داریم که نمیخواهیم آنرا در دیتابیس داشته باشیم و به عنوان فیلدی در حین اجرای کد کاربرد دارد و فقط قرار است در حافظه ذخیره شود از این annotation روی فیلد خاص استفاده میکنیم 


حالا ببینیم چطوری میشه از Column Strategy Naming استفاده کنیم :


در هایبرنیت توسط naming strategy میتوان استراتژی نام گذاری ها را تعیین کرد مثلا بگوییم نام های فیلد ها بصورت camel case است و خودش بین نام ها underline بگذارد و ...

وقتی ما هیچ استراتژی خاصی برای نام گذاری تعیین نکنیم عینا نام های فیلد و کلاس entity استفاده خواهد شد 

در هایبرنیت یکسری استراتژی های تعیین نام از قبل وجود دارد که میتوان در فایل کانفیگ هایبرنیت توسط پراپرتی hibernate.implicit_naming_strategy  از آنها استفاده کرد که دارای مقادیر مختلف default , jpa , legacy-hbm , legacy-jpa , component-path است ، مثلا وقتی از jpa استفاده کنیم هر جا به camle case برسد آنرا کوچک کرده و قبلش یک underline میگذارد 

<persistence>
    <persistence-unit name="naming">
        ...
        <properties>
            <property name="hibernate.implicit_naming_strategy"
                      value="jpa" />
            ...
        </properties>
    </persistence-unit>
</persistence> 

برای موارد پیچیده تر که مثلا میخواهیم قبل از نام تیبل ها یک _tbl اضافه کنیم باید یک کلاس کانفیگ ایجاد کنیم که از PhysicalNamingStrategyStandardImpl  ارث بری کرده باشد :

public class TablePostfixPhysicalNamingStrategy extends PhysicalNamingStrategyStandardImpl {
 
    private final static String POSTFIX = "_TBL";
     
    @Override
    public Identifier toPhysicalTableName(final Identifier identifier, final JdbcEnvironment jdbcEnv) {
        if (identifier == null) {
            return null;
        }
 
        final String newName = identifier.getText() + POSTFIX;
        return Identifier.toIdentifier(newName);
    }
 
}

و در متد  toPhysicalTableName شرایط ایجاد نام ها را مشخص میکنیم 


در Spring Boot نام گذاری روی استراتژی jpa ست شده است و قبل از camel case ها یک underline میگذارد و کل نام را حروف کوچک میکند




Id : مشخص کننده id و P.key است 


GeneratedValue : یک property بنام strategy دارد که روی Id ها استراتژی نحوه ساخته شدن Id را هنگام insert کردن مشخص میکند 

- AUTO بر اساس نوع پایگاه داده تعیین میکند که از کدام استراتژی استفاده شود

- IDENTITY بر اساس identity و شمارشی ، id ها ساخته میشود

- SEQUENCE  در پایگاه داده هایی که این قابلیت را دارند از نوع sequence استفاده میشود

- TABLE از یک جدول اضافی برای نگهداری آخرین Id استفاده میکند و sequence را شبیه سازی میکند



SequenceGenerator :  وقتی در GeneratedValue از نوع sequence گذاشتیم و بخواهیم استراتژی نوع ساخت id را از نوع sequence تعیین بکنیم از این annotation برای تعیین نام sequence استفاده میشود 

با توجه به  dialect اگر sequence ساپورت شود از آن استفاده میکند و اگر ساپورت نکند از identity استفاده میکند 

@Id
@Column(name="account_id")
@GeneratedVlue(strategy= GenerationType.SEQUENCE, generator="bnkSeqGen", allocationSize=1)
@SequenceGenerator(name="bnkSeqGen" , sequenceName = "BNK_SEQ_GEN")
private int bankAccountId ;

در هایبرنیت 5 برای بالا بردن پرفرمانس sequence strategy گزینه ای پیش فرض بنام  50 step ایجاد شده است که هر بار 50 تا id تولید میکند که هر باز برای آن select نزند باید دقت کنیم که استفاده از این گزینه در صورتی که مقدار sequence پایگاه داده 50 نیست id های منفی خواهیم داشت و میتوان از step 1 استفاده کرد که در allocationSize تعریف میشود واگر تعریف نکنیم از مقدار پیش فرض 50 استفاده میکند !! پس باید خودمان تعریفش کنیم . مثلا در دیتابیس اوراکل مقدارش 1 است 


TableGenerator : زمانی که دیتابیس از sequence حمایت نکند از این روش میتوان استفاده کرد و یک جدول با یک سطر و ستون ایجاد میکند که مقدار آخرین id را ذخیره میکند

@Id
@Column(name="account_id")
@GeneratedVlue(strategy= GenerationType.TABLE, generator="bnkTableGen")
@TableGenerator(name="bnkTableGen" , sequenceName = "BNK_TABLE_GEN")
private int bankAccountId ;



نحوه تعریف Id در کلاس های Entity :

در دنیای رابطه ای دو نوع Id داریم :


نوع اول Surrogate Key : که از یک تک ستون برای تعریف Id استفاده میشود که تا الان با این نوع کار کردیم و ساده است 


نوع دوم Composite / Compound Key : که بیش از یک ستون Id ما تشکیل میدهند که از سه طریق میتوانیم آنرا هندل کنیم : 


نوع اول : 

یک کلاس مجزا تعریف میکنیم که serializable و Embeddable@ باشد و درونش متد های hashCode و equals را هم override کنیم و درون کلاس فیلد هایی که باهم Id ما را تشکیل میدهند را ایجاد میکنیم و در کلاس Entity زیر Id@ فیلدی از جنس کلاس Embeddable قرار میدهیم و اینطوری فیلد های آن کلاس نقش Id مرکب ما را ایفا میکنند ، بدی که این روش دارد برای دسترسی به فیلد ها باید از طریق آن کلاس دسترسی پیدا کنیم و هر وقت بخواهیم رکوردی ذخیره کنیم باید از آن کلاس یک instance بسازیم


@Embeddable
public class Name implements Serializable{
    private String firstName;
    private String middleName;
    private String lastName;
    setter , getter , hashCode , equals ...
}
@Entity
@Table(name="table_name")
public class Person {

@Id
private Name name;

}


نوع دوم :

مثل روش قبل است و در کلاس Entity بجای Id@ از EmbeddedId@ استفاده کنیم 

@Entity
@Table(name="table_name")
public class Person {

@EmbeddedId
private Name name;

}



نوع سوم :

این روش از روش های قبلی بهتر است و پیچیدگی کد را کمتر میکند مثل روش اول یک کلاس میسازیم که فقط serializable است و نیازی به Embeddable@ ندارد و در کلاس Entity میتوان Id را به این صورت تعریف کرد :


public class Name implements Serializable{
    private String firstName;
    private String middleName;
    private String lastName;

// implement setter , getter , hashCode , equals 

}
@Entity
@Table(name="table_name")
@IdClass(value=Name.class)
public class Person {

    @Id
    @Column(name="first_name")
    private String firstName;
    @Id
    @Column(name="middle_name")
    private String middleName;
    @Id
    @Column(name="last_name")
    private String lastName;

}

و اینطوری به صورت مستقیم به فیلد های Id های چندگانه دسترسی بهتری داریم چون همه فیلد های کلاسی که نماینده Composite Id ما است درون کلاس entity بصورت فیلد وجود دارند و دیگر نیازی نیست یک ابجکت ثانویه new کنیم 








نظرات  (۰)

هیچ نظری هنوز ثبت نشده است

ارسال نظر

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