ORM یا Object-Relational Mapping یکی از مفاهیمی است که بسیاری از توسعهدهندگان با آن برخورد میکنند، به ویژه اگر با دیتابیسها و زبانهای برنامهنویسی شیءگرا (Object-Oriented) کار کرده باشند.
در این مطلب از وبلاگ همروش، به زبان ساده توضیح میدهیم که ORM چیست، چگونه کار میکند، مزایا و معایب آن چیست و در نهایت، راهکارهایی برای استفاده بهتر از آن ارائه میدهیم.
ORM چیست؟
ORM یا Object-Relational Mapping یک تکنیک برنامهنویسی است که به توسعهدهندگان اجازه میدهد بدون نیاز به نوشتن کدهای SQL، با دیتابیسهای رابطهای (مثل MySQL، پستگرس و SQLite) کار کنند. ORM این کار را با تبدیل دادههای دیتابیس به اشیاء در کد انجام میدهد و از این طریق دسترسی به دادهها را برای برنامهنویسان سادهتر میکند.
به زبان سادهتر، ORM یک واسطه است که به جای نوشتن کوئریهای SQL، به ما این امکان را میدهد تا از کدهای زبان برنامهنویسی استفاده کنیم و دادهها را مستقیماً به صورت اشیاء مدیریت کنیم.
چرا باید از ORM استفاده کنیم؟
- سادگی کدنویسی: با ORM، توسعهدهنده نیاز ندارد کوئریهای پیچیده SQL بنویسد و میتواند با استفاده از زبان برنامهنویسی خودش، مستقیماً دادهها را مدیریت کند.
- خوانایی بیشتر: کدها به زبان برنامهنویسی نزدیکتر و خواناتر میشوند و دیگر نیاز نیست کدهای SQL در بین کدهای برنامه قرار گیرند.
- افزایش امنیت: ORM به جلوگیری از حملات SQL Injection کمک میکند، زیرا از دستورات SQL آمادهسازی شده و ایمن استفاده میکند.
- تسهیل مهاجرت بین پایگاههای داده: به دلیل اینکه ORM سطح انتزاعی بین کد برنامه و پایگاه داده ایجاد میکند، تغییر نوع پایگاه داده (مثلاً از MySQL به PostgreSQL) آسانتر میشود.
ORM چگونه کار میکند؟
تصور کنید که شما یک جدول به نام کاربران
دارید و میخواهید دادههای این جدول را بخوانید، ویرایش کنید یا دادهای جدید در آن وارد کنید. ORM این کارها را به صورت خودکار انجام میدهد. در ORMها، هر جدول به یک کلاس تبدیل میشود و هر ستون در جدول به یک خصوصیت در آن کلاس.
مثال ساده از ORM در پایتون
فرض کنید میخواهیم یک کاربر جدید در جدول کاربران اضافه کنیم. در SQL این کار به این شکل انجام میشود:
INSERT INTO کاربران (نام, ایمیل) VALUES ('علی', 'ali@example.com');
اما با استفاده از ORM، شما میتوانید این کد را به زبان برنامهنویسی خود به شکل سادهتری بنویسید. مثلاً در زبان پایتون، با استفاده از ORM SQLAlchemy
میتوان این کار را به این شکل انجام داد:
user = User(name="علی", email="ali@example.com")
session.add(user)
session.commit()
اینجا ORM کار را به جای شما انجام میدهد و کد را به دستور SQL تبدیل کرده و به دیتابیس ارسال میکند.
آشنایی با مفاهیم اصلی در ORMها
۱. مدلها (Models)
مدلها اصلیترین بخش ORM هستند. در ORM، هر مدل نمایانگر یک جدول از دیتابیس است و هر شیء از آن مدل، معادل یک رکورد یا سطر در آن جدول است. مدلها به توسعهدهنده کمک میکنند تا به دادههای دیتابیس به صورت شیء (object) دسترسی پیدا کنند و با آنها مانند اشیاء در برنامه رفتار کنند.
۲. فیلدها (Fields)
فیلدها معادل ستونهای دیتابیس هستند و مشخص میکنند که هر ستون در جدول چه نوع دادهای را نگه میدارد (مثل IntegerField
برای اعداد صحیح یا StringField
برای متنها). در ORM، هر فیلد معمولاً به عنوان یک ویژگی (property) از کلاس مدل تعریف میشود.
۳. نگاشتها (Mappings)
نگاشت در ORM به معنای ارتباط بین جداول دیتابیس و کلاسهای مدل در کد است. ORMها این نگاشت را به صورت خودکار انجام میدهند و نیازی نیست که برنامهنویس به صورت مستقیم درگیر جزئیات دیتابیس (مانند نام ستونها یا روابط بین جداول) شود. این موضوع باعث میشود تغییر در ساختار دیتابیس راحتتر مدیریت شود.
۴. رابطهها (Relationships)
در ORM، رابطهها به صورت اشیاء نیز تعریف میشوند و به مدلها اجازه میدهند که با یکدیگر در ارتباط باشند. سه نوع اصلی رابطه در ORMها وجود دارد:
- یک به چند (One-to-Many): مثلاً هر نویسنده میتواند چند کتاب داشته باشد.
- چند به یک (Many-to-One): چندین کتاب میتوانند یک نویسنده مشترک داشته باشند.
- چند به چند (Many-to-Many): هر کتاب میتواند چندین نویسنده داشته باشد و هر نویسنده هم میتواند چندین کتاب بنویسد.
۵. کوئریها (Queries)
یکی از مهمترین ویژگیهای ORM این است که میتوان بدون نوشتن SQL به اطلاعات دیتابیس دسترسی داشت. ORMها دارای متدهایی برای ایجاد، خواندن، بهروزرسانی و حذف (CRUD) دادهها هستند که از طریق آنها میتوان انواع کوئریها را به راحتی نوشت. به عنوان مثال:
- خواندن دادهها: قطعه کد زیر تمام نویسندگان موجود در دیتابیس را برمیگرداند:
Author.objects.all()
- ایجاد دادهها: قطعه کد زیر نویسندهای جدید ایجاد میکند.
Author.objects.create(name="Jane Doe")
- بهروزرسانی دادهها: قطعه کد زیر نام نویسندهای خاص را بهروزرسانی میکند.
author.name = "Jane Smith"
author.save()
- حذف دادهها: قعطه کد زیر رکورد مربوط به نویسنده را حذف میکند.
author.delete()
۶. مدیریت تراکنشها (Transactions)
ORMها معمولاً دارای قابلیت مدیریت تراکنشها هستند که به توسعهدهندگان امکان میدهد تا یک سری عملیات دیتابیس را به صورت یکپارچه اجرا کنند. اگر یکی از عملیاتها با خطا مواجه شود، کل تراکنش لغو میشود و از ایجاد دادههای ناقص جلوگیری میشود.
۷. تجمیع و توابع تجمعی (Aggregation and Aggregative Functions)
توابع تجمیعی مانند SUM
،COUNT
،AVG
،MIN
و MAX
معمولاً به عنوان بخشی از ORMها ارائه میشوند. این توابع به برنامهنویسان کمک میکنند تا به راحتی عملیاتهای آماری روی دادهها انجام دهند.
استفاده از ORM در فریمورک جنگو
استفاده از ORM در جنگو (Django) یکی از ویژگیهای برجسته این فریمورک است که کار با دیتابیس را بهصورت شیءگرا و ساده فراهم میکند. با ORM جنگو، میتوانید به سادگی با دیتابیس ارتباط برقرار کنید و بدون نوشتن مستقیم SQL، عملیات CRUD را انجام دهید. در ادامه مهمترین ویژگیها و نحوه کار با ORM جنگو توضیح داده شده است:
۱. تعریف مدلها
در جنگو، هر مدل به عنوان یک کلاس پایتون تعریف میشود و هر فیلد به عنوان یک ویژگی کلاس مشخص میشود. همانطور که پیشتر گفته شد، این مدلها نمایانگر جداول دیتابیس هستند.
برای نمونه، فرض کنید یک مدل کتابخانهای برای مدیریت نویسندگان و کتابها داشته باشیم:
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
age = models.IntegerField()
class Book(models.Model):
title = models.CharField(max_length=200)
publication_date = models.DateField()
author = models.ForeignKey(Author, on_delete=models.CASCADE)
در اینجا:
- کلاس
Author
به عنوان یک جدول با دو ستونname
وage
تعریف شده است. - کلاس
Book
هم یک جدول با ستونهایtitle
،publication_date
و یک رابطهForeignKey
به جدول نویسندگان (Author
) دارد.
۲. ساخت جداول دیتابیس
بعد از تعریف مدلها، میتوانید با دستورات زیر جداول را در پایگاه داده ایجاد کنید:
manage.py makemigrations
python manage.py migrate
دستور makemigrations
تغییرات مدلها را به جنگو معرفی کرده و فایلهای تغییرات را ایجاد میکند. سپس با اجرای migrate
، این تغییرات در دیتابیس اعمال میشود.
۳. کار با دادهها (CRUD)
پس از تعریف مدلها و ایجاد جداول، میتوانید عملیات CRUD را انجام دهید:
الف) ایجاد داده (Create)
برای افزودن رکورد جدید به دیتابیس میتوانید به شکل زیر عمل کنید:
author = Author.objects.create(name="Jane Doe", age=45)
book = Book.objects.create(title="Python Basics", publication_date="2023-10-01", author=author)
ب) خواندن داده (Read)
برای خواندن دادهها، از روشهای مختلف کوئریگیری استفاده میشود:
دریافت همه رکوردها:
authors = Author.objects.all()
فیلتر کردن رکوردها:
young_authors = Author.objects.filter(age__lt=30)
دریافت رکورد خاص با استفاده از get
:
author = Author.objects.get(id=1)
ج) بهروزرسانی داده (Update)
برای بهروزرسانی، کافیست رکورد مورد نظر را بگیرید و فیلدهای آن را تغییر دهید و سپس ذخیره کنید:
author = Author.objects.get(id=1)
author.name = "Jane Smith"
author.save()
د) حذف داده (Delete)
برای حذف یک رکورد از دیتابیس:
author = Author.objects.get(id=1)
author.delete()
۴. رابطهها در ORM جنگو
در جنگو، میتوانید به سادگی با استفاده از روابط یک به چند، چند به چند و یک به یک، بین مدلها ارتباط برقرار کنید:
دسترسی به کتابهای یک نویسنده:
author = Author.objects.get(id=1)
books = author.book_set.all() # تمامی کتابهای مرتبط با این نویسنده
ایجاد روابط چند به چند:
اگر یک رابطه چند به چند بین دو مدل وجود داشته باشد، از ManyToManyField
استفاده میشود. برای مثال:
class Book(models.Model):
title = models.CharField(max_length=200)
authors = models.ManyToManyField(Author)
book = Book.objects.get(id=1)
author = Author.objects.get(id=2)
book.authors.add(author)
۵. کوئریهای پیشرفته
تجمیع دادهها:
from django.db.models import Count
author_count = Author.objects.aggregate(Count('id'))
ترتیبگذاری:
books = Book.objects.order_by('publication_date')
کوئریهای ترکیبی:
books = Book.objects.filter(title__contains="Python").exclude(publication_date__year=2024)
۶. مدیریت تراکنشها
برای تضمین یکپارچگی دادهها، ORM جنگو از تراکنشها نیز پشتیبانی میکند. میتوانید از transaction
استفاده کنید:
from django.db import transaction
try:
with transaction.atomic():
author = Author.objects.create(name="John Doe", age=40)
book = Book.objects.create(title="Advanced Django", publication_date="2023-11-01", author=author)
except Exception as e:
print("Error:", e)
۷. مزایای استفاده از ORM جنگو
- سادهسازی کار با پایگاه دادهها: کد شیءگرا به جای SQL.
- ایجاد خودکار جداول و مدیریت مهاجرتها: تغییر در مدلها به صورت خودکار با دستورات
makemigrations
وmigrate
اعمال میشود. - کوئریهای بهینهشده برای عملکرد بهتر: ORM جنگو کوئریها را بهینه میکند.
ORM جنگو یکی از قویترین ابزارها برای مدیریت دادهها در برنامههای وب است و استفاده از آن باعث میشود کدنویسی سریعتر، سادهتر و نگهداری کد راحتتر شود.
مزایای ORM
- سرعت توسعه بیشتر: چون کوئریهای SQL مستقیماً از کد برنامه تولید میشوند، توسعهدهنده سریعتر به نتیجه میرسد.
- امنیت بیشتر: ORMها به دلیل آمادهسازی خودکار کوئریها، تا حد زیادی در برابر حملات SQL Injection مقاوم هستند.
- پشتیبانی از مهاجرت دادهها: در صورت تغییر پایگاه داده، ORMها میتوانند کمک کنند تا نیاز به بازنویسی کدهای کمتری داشته باشید.
معایب ORMها
- کندی در عملکرد: در برنامههای بسیار بزرگ، ORMها ممکن است سرعت پایینی نسبت به کوئریهای دستنویس داشته باشند.
- پیچیدگی در پیادهسازی کوئریهای پیچیده: برخی از کوئریهای پیچیده را نمیتوان بهسادگی در ORMها پیادهسازی کرد و نیاز به دسترسی مستقیم به SQL دارید.
نکاتی برای استفاده بهتر از ORMها
- شناخت محدودیتها: همیشه باید به محدودیتهای ORM توجه داشت و در موارد ضروری کوئریهای دستنویس استفاده شود.
- توجه به بهینهسازیها: ORMها ابزارهایی برای بهینهسازی و cache کردن دادهها دارند که بهتر است از آنها استفاده کنید.
- آموزش و تمرین: هر ORM ابزارها و مفاهیم خاص خود را دارد و باید با مطالعه و تمرین، نحوه بهینه استفاده از آن را یاد گرفت.
نتیجهگیری
استفاده از ORM برای توسعهدهندگانی که میخواهند کدنویسی راحتتری در ارتباط با پایگاه داده داشته باشند، بسیار مفید است. ORM به شما این امکان را میدهد که بدون نیاز به نوشتن کوئریهای پیچیده، به سادگی و با امنیت بالا با پایگاه داده ارتباط برقرار کنید. با این حال، باید درک کافی از محدودیتها و نیازهای خاص پروژه خود داشته باشید و در صورت لزوم، از کوئریهای SQL به صورت مستقیم استفاده کنید.
امیدوارم این مطلب، مقدمهای ساده و کاربردی برای درک بهتر ORM باشد و بتواند به شما در نوشتن کدهای حرفهایتر کمک کند!