ORM কী? অ্যাপ কীভাবে ডেটাবেসের সাথে কথা বলে, সহজ ব্যাখ্যা
ORM (object-relational mapper) হলো এমন একটি কোড লাইব্রেরি, যা অ্যাপ ও একটি রিলেশনাল ডেটাবেসের মাঝখানে কাজ করে। SQL-এ ডেটাবেস কোয়েরি লেখার বদলে ডেভেলপাররা তাদের প্রোগ্রামিং ভাষার সাধারণ অবজেক্ট হিসেবে ডেটা নিয়ে কাজ করেন — db.booking.create(...) বা Booking.find(...) — আর ORM সেটিকে SQL-এ রূপান্তর করে, চালায় এবং ফলাফল আবার অবজেক্টে ফিরিয়ে দেয়। জনপ্রিয় উদাহরণ হলো TypeScript-এর জন্য Prisma ও Drizzle, Python-এর জন্য SQLAlchemy এবং C#-এর জন্য Entity Framework Core।
AI দিয়ে অ্যাপ বানালে ORM কেন গুরুত্বপূর্ণ
যখন কোনো AI অ্যাপ বিল্ডার আপনার অ্যাপে একটি ডেটাবেস যোগ করে, সাধারণত সেটির সাথে কথা বলার জন্য একটি ORM-ও যোগ করে। ORM-এর কোড আপনাকে লিখতে হবে না, তবু এটি যে আছে তা জানা কাজে আসে:
- আপনার ডেটা মডেল থাকে কোডে। ORM-এর স্কিমা ফাইল প্রায়ই আপনার অ্যাপের ডেটার সবচেয়ে স্পষ্ট বর্ণনা: কোন টেবিল আছে, প্রতিটিতে কোন ফিল্ড আছে এবং সেগুলো কীভাবে যুক্ত। AI সঠিকভাবে বুঝেছে কি না তা যাচাই করতে এটি দ্রুত পড়ে নেওয়া যায়।
- ডেটাবেসের পরিবর্তন যায় মাইগ্রেশনের মাধ্যমে। “customers-এ একটি ফোন নম্বর যোগ করো” বললে AI মডেল আপডেট করে এবং একটি মাইগ্রেশন তৈরি করে। এটি জানা থাকলে বোঝা যায় কেন কোনো পরিবর্তন লাইভে কাজ করার আগে প্রয়োগ করতে হতে পারে।
- ডিফল্টভাবে নিরাপত্তা। ORM এমনভাবে কোয়েরি তৈরি করে যা SQL injection থেকে রক্ষা করে — হাতে কোয়েরি জোড়া দেওয়া অ্যাপের অন্যতম সাধারণ নিরাপত্তা ফাঁক।
- গতির ফাঁদ। ORM সহজেই একটির বদলে শত শত ছোট কোয়েরি চালিয়ে দিতে পারে। AI-তৈরি অ্যাপে ধীর পেজের এটি একটি সাধারণ কারণ।
একটি দৈনন্দিন উপমা
ধরুন এক ব্রিটিশ পর্যটক ও এক জাপানি দোকানি, যাঁদের ভাষা এক নয়, এবং তাঁরা একজন দোভাষীর মাধ্যমে কথা বলছেন।
পর্যটক (আপনার অ্যাপ) বলেন, “আমাকে তিনটি সবচেয়ে সস্তা চা দিন।” দোভাষী (ORM) সেটিকে নির্ভুল জাপানি ভাষায় (SQL) রূপান্তর করেন, দোকানিকে (ডেটাবেস) দেন, আর উত্তরটি আবার ইংরেজিতে অনুবাদ করেন।
পর্যটককে জাপানি শিখতে হয় না, এবং বেশিরভাগ কথোপকথনে তা দরকারও হয় না। কিন্তু জটিল দর-কষাকষির সময় সরাসরি বলা সুবিধাজনক — তাই বেশিরভাগ ORM দরকার হলে কাঁচা SQL লেখার সুযোগ দেয়।
ORM কীভাবে কাজ করে
Postgres-এর মতো ডেটাবেস ডেটা রাখে টেবিলে, সারি ও কলামের আকারে, এবং SQL দিয়ে কোয়েরি করা হয়। প্রোগ্রামিং ভাষা কাজ করে অবজেক্ট নিয়ে: একটি date, একটি customer ও একটি status সহ একটি বুকিং। ORM দুইটির মধ্যে ম্যাপিং করে:
| ডেটাবেসের দিক | ORM / কোডের দিক |
|---|---|
টেবিল bookings | মডেল Booking |
| সারি (Row) | একটি বুকিং অবজেক্ট |
কলাম starts_at | ফিল্ড startsAt |
ফরেন কী customer_id | রিলেশন booking.customer |
SELECT, INSERT, UPDATE, DELETE | find, create, update, delete মেথড |
এই চারটি অপারেশনই সেই CRUD অ্যাকশন, যার ওপর প্রায় প্রতিটি অ্যাপ গড়ে উঠেছে।
একটি বাস্তব উদাহরণ: Prisma দিয়ে বুকিং
এখানে একটি সরলীকৃত Prisma স্কিমা, একটি সেলুন বুকিং অ্যাপের জন্য। এটি দুটি টেবিল ও তাদের সংযোগ বর্ণনা করে:
model Customer {
id Int @id @default(autoincrement())
name String
email String @unique
bookings Booking[]
}
model Booking {
id Int @id @default(autoincrement())
startsAt DateTime
service String
customer Customer @relation(fields: [customerId], references: [id])
customerId Int
}
সাধারণ ভাষায়: একজন গ্রাহকের একটি নাম, একটি অনন্য ইমেইল এবং অনেক বুকিং থাকে; প্রতিটি বুকিংয়ের একটি শুরুর সময় ও একটি সার্ভিস থাকে, এবং তা একজন গ্রাহকের সাথে যুক্ত।
এখন অ্যাপ চায় “লেনার আসন্ন বুকিংগুলো, সবচেয়ে কাছেরটি আগে”:
const bookings = await db.booking.findMany({
where: {
customer: { email: "lena@example.com" },
startsAt: { gte: new Date() },
},
orderBy: { startsAt: "asc" },
});
ORM এটিকে প্রায় এমন SQL-এ রূপান্তর করে, চালায় এবং বুকিং অবজেক্টের একটি তালিকা ফেরত দেয়:
SELECT b.* FROM "Booking" b
JOIN "Customer" c ON c.id = b."customerId"
WHERE c.email = $1 AND b."startsAt" >= $2
ORDER BY b."startsAt" ASC;
$1 ও $2 হলো প্লেসহোল্ডার: ইমেইল ও তারিখ কোয়েরির লেখা থেকে আলাদাভাবে পাঠানো হয় — এটিই SQL injection আটকায়।
মাইগ্রেশন
এরপর যদি বলেন “গ্রাহকরা একটি ফোন নম্বর যোগ করতে পারে”, AI Customer মডেলে phone String? যোগ করে (? মানে ঐচ্ছিক) এবং একটি মাইগ্রেশন তৈরি করে — একটি ছোট SQL স্ক্রিপ্ট, যেমন ALTER TABLE "Customer" ADD COLUMN "phone" TEXT;। মাইগ্রেশন ক্রমানুসারে সংরক্ষিত হয়, ফলে ডেটাবেসের প্রতিটি কপিকে একই গঠনে আনা যায় এবং পরিবর্তনের ইতিহাসও থাকে।
ভাষা অনুযায়ী জনপ্রিয় ORM
| ভাষা | জনপ্রিয় ORM |
|---|---|
| TypeScript / JavaScript | Prisma, Drizzle, TypeORM, Sequelize |
| Python | SQLAlchemy, Django ORM, SQLModel |
| C# | Entity Framework Core |
| Java | Hibernate (প্রায়ই Spring Data JPA-র মাধ্যমে) |
| Ruby | Active Record |
ORM কতটা SQL লুকায় তা ভিন্ন ভিন্ন। Prisma নিজস্ব স্কিমা ভাষা ও কোয়েরি শৈলী ব্যবহার করে; Drizzle ইচ্ছে করেই SQL-এর গঠনের কাছাকাছি থাকে, তবে সবকিছু টাইপ-সেফ রাখে। কোয়েরি বিল্ডার নামের হালকা টুলগুলো, যেমন TypeScript-এর Knex বা Kysely, সারিগুলোকে পূর্ণ অবজেক্টে ম্যাপ না করেই কোডে SQL তৈরিতে সাহায্য করে।
মূল শব্দ
| শব্দ | অর্থ |
|---|---|
| Model | টেবিল ও তার ফিল্ডের কোড-সংজ্ঞা। |
| Schema | সব টেবিল, ফিল্ড ও সম্পর্কের পূর্ণ বর্ণনা। |
| Relation | মডেলগুলোর মধ্যে সংযোগ, যেমন একটি বুকিং একজন গ্রাহকের। |
| Migration | ডেটাবেসের গঠন বদলানোর একটি ভার্সন-করা স্ক্রিপ্ট। |
| Query builder | পূর্ণ অবজেক্ট ম্যাপিং ছাড়াই কোডে SQL তৈরির একটি হালকা টুল। |
| N+1 problem | একটি তালিকার জন্য একটি কোয়েরি, তারপর প্রতিটি আইটেমের জন্য আরেকটি করে — বড় হলে ধীর। |
| Raw SQL | হাতে লেখা SQL, যখন ORM বাধা হয়ে দাঁড়ায়। |
সাধারণ ভুল ধারণা
- “ORM একটি ডেটাবেস।” নয়। এটি একটি অনুবাদক। আপনার তবু Postgres-এর মতো একটি ডেটাবেস দরকার।
- “ORM ব্যবহার করলে ডেটা বুঝতে হয় না।” খারাপভাবে ডিজাইন করা টেবিল ORM দিয়েও সমান যন্ত্রণার। ভালো ডেটা মডেল টুলের চেয়ে বেশি গুরুত্বপূর্ণ।
- “ORM সবসময় ধীর।” দৈনন্দিন কোয়েরি ঠিকঠাক চলে। ধীরগতি সাধারণত আসে N+1 কোয়েরির মতো প্যাটার্ন বা ইনডেক্স না থাকা থেকে, যা ঠিক করা যায়।
- “ORM মানে কখনও SQL injection ঝুঁকি নেই।” স্ট্যান্ডার্ড ORM মেথড নিরাপদ, কিন্তু ব্যবহারকারীর ইনপুট জুড়ে লেখা কাঁচা SQL এখনও বিপজ্জনক।
- “স্কিমা ফাইল বদলালে লাইভ ডেটাবেস বদলে যায়।” কেবল তখনই, যখন একটি মাইগ্রেশন তৈরি হয় এবং সেই ডেটাবেসে প্রয়োগ করা হয়।
আপনার AI বিল্ডারকে কী জিজ্ঞেস করবেন
- “ডেটাবেসের স্কিমা দেখাও এবং প্রতিটি টেবিল ও সম্পর্ক সহজ ভাষায় ব্যাখ্যা করো।”
- “এই প্রজেক্ট কোন ORM ব্যবহার করে, এবং মাইগ্রেশনগুলো কোথায়?”
- “কোনো টেবিল বদলানোর আগে বলো বিদ্যমান ডেটা প্রভাবিত হবে কি না, এবং যে কলামে ডেটা আছে সেটি জিজ্ঞেস না করে কখনও মুছো না।”
- “ধীর পেজগুলোতে N+1 কোয়েরি খুঁজে দেখো, এবং যেখানে তালিকা ফিল্টার বা সাজানো হয় সেখানে ইনডেক্স যোগ করো।”
- “নিশ্চিত করো ব্যবহারকারীর ইনপুট ব্যবহার করা প্রতিটি কোয়েরি ORM-এর মধ্য দিয়ে যায় বা প্যারামিটার ব্যবহার করে — স্ট্রিং জুড়ে তৈরি কোনো SQL নয়।”
Mythex-এ ORM
যখন আপনার অ্যাপের ডেটা সংরক্ষণ দরকার হয়, Mythex প্রজেক্টে একটি আলাদা Postgres ডেটাবেস যোগ করে — চ্যাটে জিজ্ঞেস করুন বা /database কমান্ড ব্যবহার করুন — এবং এর সংযোগের বিবরণ ওয়ার্কস্পেস ও প্রকাশিত অ্যাপে ঢুকিয়ে দেয় (Database)। এরপর এজেন্ট সেই কোড লেখে, যা আপনার ডেটা পড়ে ও সংরক্ষণ করে। আপনার কোনো পছন্দ থাকলে — “Prisma ব্যবহার করো”, “SQLAlchemy ব্যবহার করো”, বা “শুধু প্লেইন SQL, কোনো ORM নয়” — চ্যাটে বলুন। স্কিমার গঠন যাচাই করতে চাইলে এজেন্টকে ব্যাখ্যা করতে বলুন; কোড এডিটরেও ফাইলগুলো পড়া যায়। বৃহত্তর চিত্রের জন্য দেখুন ডেটাবেস কী এবং SQL বনাম NoSQL।
প্রশ্নোত্তর
সহজ ভাষায় ORM কী?
ORM (object-relational mapper) হলো একটি কোড লাইব্রেরি, যা আপনার অ্যাপ ও একটি রিলেশনাল ডেটাবেসের মাঝখানে বসে। এর সাহায্যে ডেভেলপাররা তাদের প্রোগ্রামিং ভাষার সাধারণ অবজেক্ট হিসেবে ডেটা পড়তে ও সংরক্ষণ করতে পারেন, আর পর্দার আড়ালে ORM নিজেই SQL কোয়েরি লিখে দেয়।
ORM-এর কিছু উদাহরণ কী কী?
জনপ্রিয় ORM-এর মধ্যে রয়েছে TypeScript ও JavaScript-এর জন্য Prisma ও Drizzle, Python-এর জন্য SQLAlchemy ও Django ORM, C#-এর জন্য Entity Framework Core, Java-এর জন্য Hibernate, এবং Ruby on Rails-এর Active Record।
ORM কি হাতে SQL লেখার চেয়ে ভালো?
এটি কাজের ওপর নির্ভর করে। ORM দৈনন্দিন রিড ও রাইট দ্রুত লিখতে, নিরাপদে ও সহজে বদলাতে সাহায্য করে, আর জটিল রিপোর্ট বা পারফরম্যান্স-সংবেদনশীল কোয়েরির জন্য হাতে লেখা SQL পুরো নিয়ন্ত্রণ দেয়। বেশিরভাগ ORM দরকার হলে কাঁচা SQL ব্যবহারের সুযোগ দেয়।
মাইগ্রেশন কী?
মাইগ্রেশন হলো একটি ছোট, ভার্সন-করা স্ক্রিপ্ট, যা ডেটাবেসের গঠন বদলায়, যেমন একটি টেবিল বা কলাম যোগ করা। ORM আপনার ডেটা মডেল থেকে মাইগ্রেশন তৈরি করতে পারে, ফলে ডেটাবেসের প্রতিটি কপি — ল্যাপটপে, টেস্টিংয়ে ও প্রোডাকশনে — একই গঠনে পৌঁছায়।