با استفاده از یک نمونه برنامه کاربردی مبتنی بر جاوا ۲۱ با Hibernate 6.3، مدل سازی موجودیت ها و روابط برای ماندگاری داده جاوا را شروع کنید.
Jakarta Persistence API (JPA) یک مشخصات جاوا است که شکاف بین پایگاه داده های رابطه ای و برنامه نویسی شی گرا را پر می کند. این آموزش دو قسمتی JPA را معرفی میکند و توضیح میدهد که چگونه اشیاء جاوا به عنوان موجودیتهای JPA مدلسازی میشوند، چگونه روابط موجودیت تعریف میشوند، و چگونه از EntityManager
JPA با الگوی Repository در برنامههای جاوا خود استفاده کنید. این همه اصول اولیه برای ذخیره و بارگیری وضعیت برنامه را در اختیار شما قرار می دهد.
توجه داشته باشید که این آموزش از Hibernate به عنوان ارائهدهنده JPA استفاده میکند. بیشتر مفاهیم را می توان به سایر چارچوب های ماندگاری جاوا تعمیم داد.
درباره نویسندگان
این آموزش در اصل توسط استیون هاینز نوشته شده و در JavaWorld منتشر شده است. این توسط متیو تایسون برای آخرین نسخههای جاوا و Hibernate تا زمان نگارش بهروزرسانی شده است.
روابط شی در JPA
پایگاه داده های رابطه ای به عنوان وسیله ای برای ذخیره داده های برنامه از دهه ۱۹۷۰ وجود داشته اند. در حالی که امروزه توسعه دهندگان جایگزین های زیادی برای پایگاه داده رابطه ای دارند، هنوز به طور گسترده در توسعه نرم افزار در مقیاس کوچک و بزرگ استفاده می شود.
اشیاء جاوا در زمینه پایگاه داده رابطه ای به عنوان موجودات تعریف می شوند. موجودیت ها اشیایی هستند که در جداولی قرار می گیرند که در آن ستون ها و سطرها را اشغال می کنند و در نتیجه وجودشان در برنامه بیشتر می شود. برنامه نویسان از کلیدهای خارجی و جداول پیوستن برای تعریف روابط بین موجودیت ها استفاده می کنند – یعنی روابط یک به یک، یک به چند، و چند به چند. ما از SQL (زبان جستجوی ساختاریافته) برای بازیابی و تعامل با داده ها در جداول جداگانه و در چندین جدول استفاده می کنیم.
مدل رابطهای مسطح است، در حالی که مدلهای شی نمودار هستند. توسعهدهندگان میتوانند پرسوجوهایی بنویسند تا دادهها را بازیابی کنند و اشیا را از دادههای رابطهای بسازند، و بالعکس، اما این فرآیند پر زحمت و مستعد خطا است. JPA یکی از راههای حل این مشکل است.
JPA چیست؟
به JPA چیست مراجعه کنید؟ مقدمه ای بر ماندگاری جاوا برای یادگیری در مورد تکامل JPA و چارچوب های مرتبط، از جمله EJB 3.0. و JDBC.
عدم تطابق امپدانس روابط شیء
شاید شما با اصطلاح عدم تطابق امپدانس روابط شی آشنا باشید، که به این چالش نگاشت اشیاء داده به یک پایگاه داده رابطه ای اشاره دارد. این عدم تطابق به این دلیل رخ می دهد که طراحی شی گرا به روابط یک به یک، یک به چند و چند به چند محدود نمی شود. در عوض، در طراحی شی گرا، ما به اشیا، ویژگی ها و رفتار آنها و نحوه ارتباط اشیا فکر می کنیم. دو مثال عبارتند از کپسولاسیون و ارث:
- اگر یک شی حاوی شی دیگری باشد، آن را از طریق encapsulation – یک رابطه has-a تعریف می کنیم.
- اگر شیئی تخصص شیء دیگری باشد، آن را از طریق ارث بری – یک رابطه is-a تعریف می کنیم.
تداعی، تجمیع، ترکیب، انتزاع، تعمیم، تحقق، و وابستگی ها همگی مفاهیم برنامه نویسی شی گرا هستند که نگاشت به یک مدل رابطه ای می تواند چالش برانگیز باشد.
به عبارت دیگر، نماد نقطه ساده در جاوا: myObject.anotherObject.aProperty
مستلزم مقدار زیادی کار برای یک ذخیرهسازی دادههای رابطهای است.
ORM: نگاشت شیء-رابطه ای
عدم تطابق بین طراحی شیگرا و مدلسازی پایگاهداده رابطهای منجر به ایجاد کلاسی از ابزارها شده است که بهطور خاص برای نقشهبرداری شی رابطهای (ORM) توسعه یافتهاند. ابزارهای ORM مانند Hibernate، EclipseLink، OpenJPA و MyBatis مدل های پایگاه داده رابطه ای، از جمله موجودیت ها و روابط آنها را به مدل های شی گرا ترجمه می کنند. بسیاری از این ابزارها قبل از مشخصات JPA وجود داشتند، اما بدون استاندارد، ویژگیهای آنها وابسته به فروشنده بود.
برای اولین بار به عنوان بخشی از EJB 3.0 در سال ۲۰۰۶ منتشر شد، Java Persistence API (JPA) به بنیاد Eclipse منتقل شد و در سال ۲۰۱۹ به Jakarta Persistence API تغییر نام داد. یک راه استاندارد برای حاشیه نویسی اشیاء ارائه می دهد تا بتوان آنها را نگاشت و در یک پایگاه داده رابطه ای ذخیره کرد. این مشخصات همچنین یک ساختار مشترک برای تعامل با پایگاههای داده را تعریف میکند. داشتن یک استاندارد ORM برای جاوا یکپارچگی را به پیاده سازی فروشنده می آورد، در حالی که انعطاف پذیری و افزودنی ها را نیز امکان پذیر می کند. به عنوان مثال، در حالی که مشخصات اولیه JPA برای پایگاههای داده رابطهای قابل اجرا است، برخی از پیادهسازیهای فروشنده JPA را برای استفاده با پایگاههای اطلاعاتی NoSQL گسترش دادهاند.
شروع به کار با JPA
Java Persistence API یک مشخصات است، نه یک پیاده سازی: یک انتزاع رایج را تعریف می کند که می توانید در کد خود برای تعامل با محصولات ORM استفاده کنید. این بخش برخی از بخش های مهم مشخصات JPA را بررسی می کند.
شما یاد خواهید گرفت که چگونه:
- مواد، فیلدها و کلیدهای اصلی را در پایگاه داده تعریف کنید.
- روابط بین موجودات در پایگاه داده ایجاد کنید.
- با
EntityManager
و روشهای آن کار کنید.
تعریف موجودیت ها
برای تعریف یک موجودیت، باید کلاسی ایجاد کنید که با حاشیه نویسی @Entity
حاشیه نویسی شده باشد. حاشیه نویسی @Entity
یک حاشیه نویسی نشانگر است که برای کشف موجودیت های پایدار استفاده می شود. به عنوان مثال، اگر می خواهید یک موجودیت کتاب ایجاد کنید، آن را به صورت زیر حاشیه نویسی کنید:
@Entity
public class Book {
...
}
بهطور پیشفرض، این موجودیت همانطور که با نام کلاس مشخص میشود، به جدول Book نگاشت میشود. اگر میخواهید این موجودیت را به جدول دیگری (و به صورت اختیاری، طرحی خاص) نگاشت کنید، میتوانید از حاشیهنویسی @table
استفاده کنید. در اینجا نحوه نگاشت کلاس Book
به جدول BOOKS
آمده است:
@Entity
@Table(name="BOOKS")
public class Book {
...
}
اگر جدول BOOKS
در طرح PUBLISHING
بود، میتوانید طرح را به حاشیهنویسی @Table
اضافه کنید:
@Table(name="BOOKS", schema="PUBLISHING")
نگاشت فیلدها به ستون ها
با نگاشت موجودیت به جدول، وظیفه بعدی شما این است که فیلدهای آن را تعریف کنید. فیلدها به عنوان متغیرهای عضو در کلاس تعریف می شوند که نام هر فیلد به نام ستون در جدول نگاشت می شود. همانطور که در اینجا نشان داده شده است، می توانید با استفاده از حاشیه نویسی @Column
، این نگاشت پیش فرض را لغو کنید:
@Entity
@Table(name="BOOKS")
public class Book {
private String name;
@Column(name="ISBN_NUMBER")
private String isbn;
...
}
در این مثال، ما نگاشت پیشفرض را برای ویژگی name
پذیرفتهایم اما یک نگاشت سفارشی را برای ویژگی isbn
تعیین کردهایم. ویژگی name
به ستون “name” نگاشت می شود، اما ویژگی isbn
به ستون ISBN_NUMBER نگاشت می شود.
حاشیه نویسی @Column
به ما امکان می دهد ویژگی های اضافی فیلد یا ستون را تعریف کنیم، از جمله طول، تهی بودن آن، اینکه آیا باید منحصر به فرد باشد، دقت و مقیاس آن (اگر مقدار اعشاری باشد) )، اینکه آیا قابل درج و به روز رسانی است، و غیره.
مشخص کردن کلید اصلی
یکی از الزامات جدول پایگاه داده رابطه ای این است که باید دارای یک کلید اصلی یا کلیدی باشد که به طور منحصر به فرد یک ردیف خاص در پایگاه داده را شناسایی کند. در JPA، از حاشیه نویسی @Id
برای تعیین فیلدی به عنوان کلید اصلی جدول استفاده می کنیم. کلید اصلی باید از نوع ابتدایی جاوا، یک پوشش اولیه مانند Integer
یا Long
، یک String
، یک Date باشد. code>، یک
BigInteger
یا یک BigDecimal
.
در این مثال، ویژگی id
را که یک Integer
است به ستون ID در جدول BOOKS
نگاشت میکنیم: p>
@Entity
@Table(name="BOOKS")
public class Book {
@Id
private Integer id;
private String name;
@Column(name="ISBN_NUMBER")
private String isbn;
...
}
همچنین میتوان حاشیهنویسی @Id
را با حاشیهنویسی @Column
ترکیب کرد تا نگاشت نام ستون کلید اصلی را بازنویسی کرد.
روابط موجود در JPA
اکنون که می دانید چگونه یک موجودیت را تعریف کنید، بیایید نحوه ایجاد روابط بین موجودیت ها را بررسی کنیم. JPA چهار حاشیه نویسی را برای تعریف روابط بین موجودیت ها تعریف می کند:
@OneToOne
@OneToMany
@ManyToOne
@ManyToMany
روابط یک به یک
حاشیه نویسی @OneToOne
برای تعریف رابطه یک به یک بین دو موجودیت استفاده می شود. به عنوان مثال، ممکن است یک موجودیت User
داشته باشید که حاوی نام، ایمیل و رمز عبور کاربر است، اما ممکن است بخواهید اطلاعات اضافی درباره یک کاربر (مانند سن، جنسیت، و رنگ مورد علاقه) را در آن نگهداری کنید. یک موجودیت UserProfile
جداگانه. حاشیه نویسی @OneToOne
تجزیه داده ها و موجودیت های شما را به این روش تسهیل می کند.
کلاس User
زیر دارای یک نمونه UserProfile
است. UserProfile
به یک نمونه User
نگاشت می شود.
@Entity
public class User {
@Id
private Integer id;
private String email;
private String name;
private String password;
@OneToOne(mappedBy="user")
private UserProfile profile;
...
}
@Entity
public class UserProfile {
@Id
private Integer id;
private int age;
private String gender;
private String favoriteColor;
@OneToOne
private User user;
...
}
ارائهدهنده JPA از فیلد کاربری UserProfile
برای نگاشت UserProfile
به User
استفاده میکند. نقشه برداری در ویژگی mappedBy
در حاشیه نویسی @OneToOne
مشخص شده است.
روابط یک به چند و چند به یک
حاشیه نویسی @OneToMany
و @ManyToOne
جنبه های مختلف یک رابطه را تسهیل می کند. مثالی را در نظر بگیرید که در آن یک کتاب می تواند فقط یک نویسنده داشته باشد، اما یک نویسنده ممکن است کتاب های زیادی داشته باشد. موجودیت Book
یک رابطه @ManyToOne
با Author
و موجودیت Author
یک @ تعریف میکند. رابطه OneToMany
با Book
:
@Entity
public class Book {
@Id
private Integer id;
private String name;
@ManyToOne
@JoinColumn(name="AUTHOR_ID")
private Author author;
...
}
@Entity
public class Author {
@Id
@GeneratedValue
private Integer id;
private String name;
@OneToMany(mappedBy = "author")
private List<Book> books = new ArrayList<>();
...
}
در این مورد، کلاس Author
فهرستی از تمام کتابهای نوشته شده توسط آن نویسنده را نگه میدارد و کلاس Book
به نویسندهی مجرد خود اشاره میکند. علاوه بر این، @JoinColumn
نام ستون را در جدول Book
برای ذخیره شناسه Author
مشخص میکند.
روابط چند به چند
در نهایت، حاشیه نویسی @ManyToMany
یک رابطه چند به چند بین موجودیت ها را تسهیل می کند. در اینجا یک مورد وجود دارد که در آن موجودیت Book
دارای چندین نویسنده
است:
@Entity
public class Book {
@Id
private Integer id;
private String name;
@ManyToMany
@JoinTable(name="BOOK_AUTHORS",
joinColumns=@JoinColumn(name="BOOK_ID"),
inverseJoinColumns=@JoinColumn(name="AUTHOR_ID"))
private Set<Author> authors = new HashSet<>();
...
}
@Entity
public class Author {
@Id
@GeneratedValue
private Integer id;
private String name;
@ManyToMany(mappedBy = "author")
private Set<Book> books = new HashSet<>();
...
}
در این مثال، ما یک جدول جدید، BOOK_AUTHORS
، با دو ستون ایجاد می کنیم: BOOK_ID
و AUTHOR_ID
. استفاده از ویژگیهای joinColumns
و inverseJoinColumns
به چارچوب JPA شما میگوید که چگونه این کلاسها را در یک رابطه چند به چند نگاشت کنید. حاشیه نویسی @ManyToMany
در کلاس Author
به فیلدی در کلاس Book
اشاره می کند که رابطه را مدیریت می کند، یعنی نویسندگان دارایی.
کار با EntityManager
EntityManager
کلاسی است که تعاملات پایگاه داده را در JPA انجام می دهد. از طریق یک فایل پیکربندی به نام persistence.xml
یا با استفاده از حاشیه نویسی مقداردهی اولیه می شود. هر رویکرد مزایایی دارد. حاشیه نویسی پیکربندی را نزدیک به کلاس پیکربندی شده نگه می دارد، که ساده تر است، در حالی که فایل XML پیکربندی را خارج از کد نگه می دارد و در برنامه های مختلف قابل اشتراک گذاری است.
در این مثال از persistence.xml
استفاده خواهیم کرد. فایل در پوشه META-INF
در CLASSPATH
شما، که معمولاً در فایل JAR یا WAR شما بسته بندی می شود، یافت می شود. فایل persistence.xml
حاوی موارد زیر است:
- نام "واحد پایداری"، که چارچوب ماندگاری مورد استفاده شما را مشخص میکند، مانند Hibernate یا EclipseLink.
- مجموعه ای از ویژگی ها که نحوه اتصال به پایگاه داده شما و همچنین هرگونه سفارشی سازی در چارچوب ماندگاری را مشخص می کند.
- لیستی از کلاس های موجود در پروژه شما.
بیایید به یک مثال نگاه کنیم.
پیکربندی EntityManager
ابتدا، یک EntityManager
ایجاد می کنیم. چند راه برای انجام این کار وجود دارد، از جمله استفاده از EntityManagerFactory
که از کلاس Persistence
بازیابی شده است. در بسیاری از سناریوها، این کلاس با یک ظرف IoC مانند Spring یا با Java CDI (Contexts and Dependency Injection) تزریق می شود. برای سادگی در برنامه مستقل خود، بیایید EntityManager
را در یک مکان تعریف کنیم، و سپس از طریق EntityManagerFactory
به آن دسترسی پیدا کنیم، مانند:
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("Books");
EntityManager entityManager = entityManagerFactory.createEntityManager();
در این مورد، ما یک EntityManager
ایجاد کردهایم که به واحد ماندگاری "Books" متصل است. به زودی EntityManager
را در عمل خواهید دید.
کلاس EntityManager
نحوه تعامل نرم افزار ما با پایگاه داده از طریق موجودیت های JPA را تعریف می کند. در اینجا برخی از روش های استفاده شده توسط EntityManager
آمده است:
پست های مرتبط
ماندگاری جاوا با JPA و Hibernate: نهادها و روابط
ماندگاری جاوا با JPA و Hibernate: نهادها و روابط
ماندگاری جاوا با JPA و Hibernate: نهادها و روابط