Hibernate এ ইনহেরিটেন্স (Inheritance) মডেলিং তিনটি প্রধান টেকনিক ব্যবহার করে করা যায়। এগুলি হল Table Per Class Hierarchy, Table Per Subclass, এবং Table Per Concrete Class। এই টেকনিকগুলি ইনহেরিটেন্স হায়ারার্কি কিভাবে ডেটাবেস টেবিলে মানচিত্রিত হবে তা নির্ধারণ করে। এই তিনটি পদ্ধতির মধ্যে পার্থক্য রয়েছে ডেটাবেসে কিভাবে ডেটা সঞ্চিত হবে এবং কিভাবে সম্পর্কিত ডেটা অনুরোধ করা হবে।
1. Table Per Class Hierarchy (TPC)
এই পদ্ধতিতে, সমস্ত সাবক্লাসের জন্য একটি মাত্র টেবিল ব্যবহৃত হয়। এই টেবিলের মধ্যে সকল বৈশিষ্ট্য (প্রোপার্টি) রাখা হয়, এমনকি বেস ক্লাসেরও। Discriminator কলাম ব্যবহার করে প্রতিটি রেকর্ডের ধরন (কোন ক্লাসের অন্তর্গত) চিহ্নিত করা হয়।
সুবিধা:
- একটিমাত্র টেবিল ব্যবহৃত হওয়ায়, টেবিল স্ট্রাকচার সহজ।
- পারফরম্যান্স ভালো হতে পারে, কারণ শুধুমাত্র একটি টেবিলেই সমস্ত তথ্য সন্নিবেশিত থাকে।
অসুবিধা:
- যদি ক্লাস হায়ারার্কি বড় হয়, তাহলে টেবিলের কলাম সংখ্যা অনেক বেশি হয়ে যেতে পারে।
- ডেটা রিডানডেন্স (Data Redundancy) বৃদ্ধি পায়।
2. Table Per Subclass (TPS)
এই পদ্ধতিতে, প্রতিটি সাবক্লাসের জন্য একটি আলাদা টেবিল তৈরি করা হয়। বেস ক্লাসের জন্য একটি টেবিল থাকবে এবং প্রতিটি সাবক্লাসের জন্য একটি আলাদা টেবিল থাকবে, যেগুলো শুধুমাত্র তাদের নিজস্ব বৈশিষ্ট্যগুলোই ধারণ করবে।
সুবিধা:
- ডেটা রিডানডেন্স কম থাকে, কারণ প্রতিটি টেবিল শুধুমাত্র প্রয়োজনীয় ডেটা ধারণ করে।
- ক্লাসের জন্য আলাদা টেবিল থাকায়, ভবিষ্যতে স্কিমা পরিবর্তন করা সহজ।
অসুবিধা:
- কুয়েরি লেখার সময় কিছুটা জটিলতা হতে পারে, কারণ সাবক্লাসগুলোর টেবিল থেকে ডেটা আনতে JOIN অপারেশন করতে হয়।
3. Table Per Concrete Class
এই পদ্ধতিতে, প্রতিটি কনক্রিট (অথবা বাস্তবায়িত) ক্লাসের জন্য আলাদা টেবিল তৈরি হয়। এই টেবিলগুলো শুধুমাত্র তাদের নিজস্ব ডেটা ধারণ করে এবং অন্য ক্লাসের ডেটার জন্য কোন রেফারেন্স রাখে না।
সুবিধা:
- সাবক্লাসের টেবিলগুলি একে অপর থেকে স্বাধীন, যার ফলে টেবিলের ডিজাইন সোজা।
- ইনহেরিটেন্স সম্পর্কিত কোনো সমস্যা বা জটিলতা থাকে না, কারণ ডেটাবেসে একাধিক টেবিল থাকে।
অসুবিধা:
- ডেটা রিডানডেন্স বৃদ্ধি পায়, কারণ প্রতিটি কনক্রিট ক্লাসের জন্য পুরো ডেটা সন্নিবেশিত হয়।
- কুয়েরি পারফরম্যান্স খারাপ হতে পারে, কারণ একই ধরনের তথ্য একাধিক টেবিলে সংরক্ষিত থাকে।
4. কোন পদ্ধতি ব্যবহার করবেন?
- যদি আপনার ইনহেরিটেন্স হায়ারার্কি ছোট এবং আপনি একটি সহজ টেবিল স্ট্রাকচার চান, তবে Table Per Class Hierarchy সবচেয়ে ভালো পদ্ধতি হতে পারে।
- যদি আপনি ডেটার রিডানডেন্স কমাতে চান এবং প্রতিটি সাবক্লাসের জন্য আলাদা টেবিল রাখতে চান, তবে Table Per Subclass উপযুক্ত।
- যদি আপনার কনক্রিট ক্লাসগুলি খুব আলাদা এবং তাদের মধ্যে একে অপরের সাথে সম্পর্ক কম থাকে, তবে Table Per Concrete Class ব্যবহার করা যেতে পারে।
এই তিনটি পদ্ধতির প্রতিটিরই নিজের নিজস্ব ব্যবহারিক ক্ষেত্র রয়েছে, এবং সঠিক পদ্ধতি নির্বাচন ডেটাবেসের কাঠামো এবং প্রয়োজনে নির্ভর করে।
Table Per Class Hierarchy (TPC) হল একটি হাইব্রিড ইনহেরিটেন্স মডেল যেখানে পুরো ক্লাস হায়ারার্কি একটিমাত্র টেবিলের মধ্যে সংরক্ষিত হয়। এই মডেলটি সাধারণত ছোট অ্যাপ্লিকেশনগুলির জন্য ব্যবহৃত হয় যেখানে একাধিক ক্লাসের ডেটা একই টেবিলের মধ্যে সংরক্ষিত থাকে।
NHibernate এ Table Per Class Hierarchy মডেলটি সাধারণত Discriminator কলাম ব্যবহার করে বাস্তবায়িত করা হয়, যা ক্লাসের ধরন বা টেবিলের বিভিন্ন সাবক্লাসের মধ্যে পার্থক্য তৈরি করে।
Table Per Class Hierarchy Mapping এর সুবিধা
- সহজ টেবিল স্ট্রাকচার: একাধিক ক্লাসের জন্য একটি টেবিল তৈরি হয়, যা ডেটাবেসের জটিলতা কমাতে সাহায্য করে।
- ভাল পারফরম্যান্স: যেহেতু একটিমাত্র টেবিল ব্যবহৃত হয়, তাই কুয়েরি পারফরম্যান্স অনেক ভালো হতে পারে।
- ডেটা রিডানডেন্স: এই মডেলে, ডেটা রিডানডেন্স কমে যায়, কারণ একই টেবিলের মধ্যে সব ডেটা থাকে।
TPC মডেল কিভাবে কাজ করে
এখানে Employee এবং তার FullTimeEmployee এবং PartTimeEmployee এর উদাহরণ ব্যবহার করা হবে।
- Employee ক্লাসটি একটি বেস ক্লাস হিসেবে কাজ করবে।
- FullTimeEmployee এবং PartTimeEmployee ক্লাসগুলো হল সাবক্লাস, যেগুলোর সব ডেটা Employee টেবিলেই সঞ্চিত থাকবে।
1. ক্লাস মডেল তৈরি
প্রথমে, তিনটি ক্লাস তৈরি করা হবে — Employee, FullTimeEmployee, এবং PartTimeEmployee।
public class Employee
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
public class FullTimeEmployee : Employee
{
public virtual double Salary { get; set; }
}
public class PartTimeEmployee : Employee
{
public virtual double HourlyRate { get; set; }
}
এখানে:
- Employee হল বেস ক্লাস।
- FullTimeEmployee এবং PartTimeEmployee হল সাবক্লাস যেগুলি Employee এর বৈশিষ্ট্যগুলি উত্তরাধিকারসূত্রে গ্রহণ করে।
2. hibernate.cfg.xml ফাইল কনফিগার করা
NHibernate এ Table Per Class Hierarchy ম্যাপিং করতে, আপনাকে Discriminator কলাম কনফিগার করতে হবে যা প্রতিটি সাবক্লাসের মধ্যে পার্থক্য করবে। এই উদাহরণে, Employee টেবিলটি তিনটি ক্লাসের জন্য একটি টেবিল হবে এবং Discriminator কলামটি ঠিক করবে কোন সাবক্লাসের ডেটা।
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="hibernate.dialect">NHibernate.Dialect.MsSql2008Dialect</property>
<property name="hibernate.connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<property name="hibernate.connection.connection_string">Server=yourserver;Database=yourdb;Integrated Security=True;</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- Discriminator সেটিংস -->
<mapping class="FullTimeEmployee">
<join table="Employee">
<key column="Id"/>
<discriminator column="EmployeeType" type="string"/>
</join>
</mapping>
<mapping class="PartTimeEmployee">
<join table="Employee">
<key column="Id"/>
<discriminator column="EmployeeType" type="string"/>
</join>
</mapping>
</session-factory>
</hibernate-configuration>
এখানে:
- Discriminator কলামটি EmployeeType নামে তৈরি করা হয়েছে, যা সিদ্ধান্ত নেবে কোন ক্লাসের ডেটা সেই রেকর্ডের জন্য প্রযোজ্য।
- hibernate.hbm2ddl.auto প্রপার্টিটি
updateহিসেবে সেট করা হয়েছে, যাতে NHibernate স্বয়ংক্রিয়ভাবে ডেটাবেসের স্কিমা আপডেট করে।
3. Database Schema
এই মডেলে, Employee টেবিলটি তৈরি হবে যা তিনটি ক্লাসের তথ্য ধারণ করবে। টেবিলটি এমন হবে:
CREATE TABLE Employee (
Id INT PRIMARY KEY,
Name VARCHAR(255),
Salary FLOAT, -- FullTimeEmployee এর জন্য
HourlyRate FLOAT, -- PartTimeEmployee এর জন্য
EmployeeType VARCHAR(50) -- Discriminator কলাম
);
এই টেবিলটি তিনটি সাবক্লাসের (FullTimeEmployee, PartTimeEmployee, Employee) তথ্য সংরক্ষণ করবে। EmployeeType কলামটি ব্যবহার করা হবে বিভিন্ন সাবক্লাসের মধ্যে পার্থক্য করতে।
4. Data Insert এবং Select
FullTimeEmployee এবং PartTimeEmployee এর জন্য ডেটা সন্নিবেশ ও পড়া খুবই সহজ হবে, কারণ সমস্ত ডেটা Employee টেবিলে একত্রিত হয়ে থাকবে।
Data Insert Example:
public void InsertEmployee()
{
using (ISession session = NHibernateHelper.SessionFactory.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
try
{
var fullTimeEmployee = new FullTimeEmployee
{
Name = "John Doe",
Salary = 50000
};
session.Save(fullTimeEmployee);
var partTimeEmployee = new PartTimeEmployee
{
Name = "Jane Smith",
HourlyRate = 20
};
session.Save(partTimeEmployee);
transaction.Commit();
}
catch (Exception)
{
transaction.Rollback();
throw;
}
}
}
Data Read Example:
public Employee GetEmployeeById(int id)
{
using (ISession session = NHibernateHelper.SessionFactory.OpenSession())
{
return session.Get<Employee>(id); // সকল Employee সন্নিবেশ করা যাবে
}
}
5. Table Per Class Hierarchy এর সীমাবদ্ধতা
- ডেটা রিডানডেন্স: একই টেবিলের মধ্যে একাধিক ক্লাসের ডেটা থাকলে কিছু রিডানডেন্স হতে পারে।
- মেডেল তৈরি করা: যদি খুব জটিল ইনহেরিটেন্স হায়ারার্কি থাকে তবে একটিমাত্র টেবিলের মধ্যে সব ডেটা রাখা কঠিন হয়ে যেতে পারে।
Table Per Class Hierarchy Mapping হলো এমন একটি পদ্ধতি যা ছোট অ্যাপ্লিকেশন বা সহজ ক্লাস হায়ারার্কির জন্য বেশ কার্যকর। তবে বড় এবং জটিল ডেটাবেসের জন্য এই পদ্ধতি কিছু সীমাবদ্ধতা তৈরি করতে পারে, এবং এমন পরিস্থিতিতে অন্যান্য ইনহেরিটেন্স ম্যাপিং পদ্ধতি (যেমন Table Per Subclass বা Table Per Concrete Class) ব্যবহার করা হতে পারে।
Table Per Subclass (TPS) একটি Inheritance Mapping Strategy যেখানে এক্সটেনডেড ক্লাসের জন্য আলাদা আলাদা টেবিল তৈরি করা হয়, কিন্তু সব টেবিলের মধ্যে সম্পর্ক স্থাপিত থাকে। এই কৌশলে, মূল ক্লাসের জন্য একটি টেবিল তৈরি হয় এবং সাবক্লাসের জন্য আলাদা টেবিল তৈরি হয়, যেখানে মূল ক্লাসের ফিল্ডগুলি সাবক্লাসে ইনহেরিট করা হয় এবং প্রত্যেক সাবক্লাসের জন্য নিজের ফিল্ড থাকে।
NHibernate এ Table Per Subclass Mapping এর মাধ্যমে আপনি সহজেই ইনহেরিটেন্স স্ট্রাকচার তৈরি করতে পারেন যেখানে সব সাবক্লাসের ডেটা তাদের নিজস্ব টেবিলে সেভ করা হয়, তবে সাধারণ তথ্য মূল টেবিলে থাকে।
Table Per Subclass Mapping এর উদাহরণ
ধরা যাক, আমাদের একটি Employee ক্লাস এবং এর দুটি সাবক্লাস Manager এবং Developer আছে। আমরা চাই যে, Employee এর জন্য একটি টেবিল এবং Manager ও Developer এর জন্য আলাদা টেবিল তৈরি করা হোক।
1. Entity Classes তৈরি করা
প্রথমে আমরা Employee, Manager, এবং Developer ক্লাস তৈরি করি।
public class Employee
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual string Position { get; set; }
}
public class Manager : Employee
{
public virtual int TeamSize { get; set; }
}
public class Developer : Employee
{
public virtual string ProgrammingLanguage { get; set; }
}
এখানে:
Employeeহল বেস ক্লাস, এবংManagerওDeveloperসাবক্লাস।Managerএর জন্য একটি অতিরিক্ত প্রপার্টিTeamSizeএবংDeveloperএর জন্যProgrammingLanguageপ্রপার্টি রয়েছে।
2. Mapping File তৈরি করা (XML Mapping)
এখন আমরা Mapping File তৈরি করব। এখানে আমরা Employee ক্লাসের জন্য একটি টেবিল এবং Manager ও Developer এর জন্য আলাদা আলাদা টেবিল তৈরি করব। Mapping ফাইলের মাধ্যমে NHibernate জানবে যে কোন ক্লাসের জন্য কোন টেবিল তৈরি হবে।
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<!-- Employee class to table mapping -->
<class name="Employee" table="Employees">
<id name="Id" column="EmployeeID">
<generator class="identity"/>
</id>
<property name="Name" column="Name"/>
<property name="Position" column="Position"/>
</class>
<!-- Manager class to its own table mapping -->
<subclass name="Manager" table="Managers">
<key column="EmployeeID"/>
<property name="TeamSize" column="TeamSize"/>
</subclass>
<!-- Developer class to its own table mapping -->
<subclass name="Developer" table="Developers">
<key column="EmployeeID"/>
<property name="ProgrammingLanguage" column="ProgrammingLanguage"/>
</subclass>
</hibernate-mapping>
এখানে:
Employeeক্লাসটিEmployeesটেবিলের সাথে ম্যাপ করা হয়েছে।ManagerএবংDeveloperক্লাস দুটি আলাদা টেবিলManagersএবংDevelopersএর সাথে ম্যাপ করা হয়েছে।<subclass>ট্যাগের মাধ্যমে আমরা সাবক্লাসগুলির জন্য আলাদা টেবিল নির্দেশ করেছি এবং তাদের প্রোপার্টিগুলি ম্যাপ করেছি।
3. Fluent Mapping ব্যবহার করা
Fluent Mapping এর মাধ্যমে একই কাজ করা সম্ভব। নিচে FluentNHibernate ব্যবহার করে এই মডেলটি ম্যাপ করা হয়েছে:
using FluentNHibernate.Mapping;
public class EmployeeMap : ClassMap<Employee>
{
public EmployeeMap()
{
Table("Employees");
Id(x => x.Id).Column("EmployeeID").GeneratedBy.Identity();
Map(x => x.Name).Column("Name");
Map(x => x.Position).Column("Position");
}
}
public class ManagerMap : SubclassMap<Manager>
{
public ManagerMap()
{
Table("Managers");
KeyColumn("EmployeeID");
Map(x => x.TeamSize).Column("TeamSize");
}
}
public class DeveloperMap : SubclassMap<Developer>
{
public DeveloperMap()
{
Table("Developers");
KeyColumn("EmployeeID");
Map(x => x.ProgrammingLanguage).Column("ProgrammingLanguage");
}
}
এখানে:
- EmployeeMap ক্লাসটি
Employeeটেবিলের সাথে সম্পর্কিত। - ManagerMap এবং DeveloperMap সাবক্লাসের জন্য আলাদা টেবিল নির্দেশ করেছে।
KeyColumn("EmployeeID")নির্দেশ করে যে, সাবক্লাসগুলির জন্যEmployeeIDমূল টেবিলের প্রাইমারি কী হবে।
4. Table Per Subclass এর সুবিধা ও অসুবিধা
সুবিধা:
- Data Integrity: সব সাবক্লাসের জন্য নিজস্ব টেবিল থাকা সত্ত্বেও তারা মূল ক্লাসের সাথে সম্পর্কিত থাকে, তাই ডেটাবেসে ডেটা সমন্বিত থাকে।
- Performance: যেহেতু সাবক্লাসের জন্য আলাদা টেবিল রয়েছে, এতে শুধুমাত্র প্রয়োজনীয় ডেটা পড়া বা আপডেট করা হয়, যেটি পারফরম্যান্সের জন্য উপকারী।
- Easy to Extend: নতুন সাবক্লাস যোগ করা সহজ, কারণ শুধুমাত্র নতুন টেবিল এবং ম্যাপিং ফাইল যোগ করতে হয়।
অসুবিধা:
- Complex Queries: যখন একাধিক সাবক্লাসের ডেটা একসাথে প্রয়োজন হয়, তখন টেবিলগুলির মধ্যে জয়েন (join) করতে হতে পারে, যা কিছুটা জটিল হতে পারে।
- Redundant Columns: সাবক্লাসের মধ্যে একাধিক টেবিলের কলাম পুণরাবৃত্তি হতে পারে (যেমন,
EmployeeID), যার কারণে কিছুটা অতিরিক্ত স্টোরেজ ব্যবহার হতে পারে।
Table Per Subclass মেপিং NHibernate এর জন্য একটি শক্তিশালী কৌশল, যেটি ইনহেরিটেন্স ভিত্তিক ডেটাবেস ডিজাইনকে বাস্তবায়ন করতে সহায়তা করে।
Table Per Concrete Class (TPC) মডেল হল একটি ORM কৌশল যেখানে প্রতি কনক্রিট ক্লাসের জন্য আলাদা টেবিল তৈরি করা হয়। এতে, প্রতিটি কনক্রিট ক্লাস তার নিজস্ব টেবিল ধারণ করে এবং এতে সমস্ত প্রপার্টি সংরক্ষিত থাকে, যার মধ্যে সত্ত্বেও পূর্ববর্তী ক্লাসের উত্তরাধিকারসূত্রে প্রাপ্ত প্রপার্টিগুলি অন্তর্ভুক্ত থাকে না। এই কৌশলটি Inheritance Mapping এর একটি অংশ এবং যখন আপনি টেবিলগুলোকে সহজ ও স্বতন্ত্র রাখতে চান তখন এটি ব্যবহার করা হয়।
এখানে, Table Per Concrete Class কৌশলটি ব্যবহার করার জন্য NHibernate এর মাধ্যমে একটি উদাহরণ দেওয়া হলো।
1. Inheritance Structure
ধরা যাক, আপনি দুটি কনক্রিট ক্লাস তৈরি করেছেন: Employee এবং Manager। Manager ক্লাসটি Employee ক্লাস থেকে উত্তরাধিকারী, তবে এই দুটি ক্লাসের জন্য আলাদা আলাদা টেবিল থাকবে।
ক্লাস মডেল:
public class Employee
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual decimal Salary { get; set; }
}
public class Manager : Employee
{
public virtual string Department { get; set; }
}
এখানে, Manager ক্লাসটি Employee ক্লাস থেকে উত্তরাধিকারসূত্রে প্রাপ্ত, তবে দুটি আলাদা টেবিল থাকবে, একটিতে Employee এবং আরেকটিতে Manager এর ডেটা সংরক্ষিত হবে।
2. NHibernate Mapping
Table Per Concrete Class কৌশলটি ব্যবহার করতে, আপনাকে প্রতিটি কনক্রিট ক্লাসের জন্য আলাদা আলাদা টেবিল এবং ম্যাপিং কনফিগারেশন তৈরি করতে হবে।
Employee Class Mapping:
public class EmployeeMap : ClassMap<Employee>
{
public EmployeeMap()
{
Table("Employees"); // Employee টেবিল
Id(x => x.Id);
Map(x => x.Name);
Map(x => x.Salary);
}
}
Manager Class Mapping:
public class ManagerMap : ClassMap<Manager>
{
public ManagerMap()
{
Table("Managers"); // Manager টেবিল
Id(x => x.Id);
Map(x => x.Name);
Map(x => x.Salary);
Map(x => x.Department); // Manager এর Department
}
}
এখানে, EmployeeMap এবং ManagerMap ক্লাসগুলো আলাদা টেবিল ম্যাপিং কনফিগারেশন করে, এবং Employee এবং Manager এর জন্য আলাদা টেবিল তৈরি করে।
3. Database Structure
উপরের ম্যাপিং কনফিগারেশনের ভিত্তিতে, আপনি দুটি আলাদা টেবিল পাবেন:
Employees Table:
| Id | Name | Salary |
|---|---|---|
| 1 | John Doe | 50000 |
| 2 | Jane Smith | 60000 |
Managers Table:
| Id | Name | Salary | Department |
|---|---|---|---|
| 1 | Sarah Lee | 80000 | HR |
4. Querying Data
যেহেতু এই কৌশলে Employee এবং Manager এর জন্য আলাদা টেবিল রয়েছে, আপনি পৃথকভাবে তাদের সারণী থেকে ডেটা রিট্রাইভ করতে পারবেন। উদাহরণস্বরূপ, Employee টেবিল থেকে সমস্ত Employee তথ্য পাওয়া যাবে, এবং Manager টেবিল থেকে শুধুমাত্র Manager তথ্য পাওয়া যাবে।
using (var session = NHibernateHelper.SessionFactory.OpenSession())
{
// All Employees
var employees = session.Query<Employee>().ToList();
// All Managers
var managers = session.Query<Manager>().ToList();
}
এখানে, employees এবং managers দুটি আলাদা তালিকা হিসেবে ডেটা রিট্রাইভ করবে, কারণ তারা আলাদা টেবিল থেকে আসছে।
5. Table Per Concrete Class এর সুবিধা
- ডেটাবেস পারফরম্যান্স: এই কৌশলটি পারফরম্যান্সের দৃষ্টিকোণ থেকে উপকারী হতে পারে, কারণ এটি শুধুমাত্র একক কনক্রিট ক্লাসের জন্য ডেটা ধারণ করে, এবং অন্যান্য শ্রেণীগুলোর জন্য একত্রিত টেবিলের তুলনায় ডেটাবেসের অ্যাক্সেস দ্রুত হতে পারে।
- টেবিলের সরলতা: যদি আপনি বিভিন্ন কনক্রিট ক্লাসের জন্য আলাদা আলাদা ডেটা সংরক্ষণ করতে চান এবং তাদের মধ্যে উত্তরাধিকারী সম্পর্ক না রেখে একে অপরকে স্বাধীনভাবে সংরক্ষণ করতে চান, তাহলে এটি একটি ভালো পছন্দ হতে পারে।
6. Table Per Concrete Class এর সীমাবদ্ধতা
- ডুপ্লিকেট কলাম: প্রতি কনক্রিট ক্লাসের জন্য আলাদা টেবিল থাকলে, আপনি যদি একই বৈশিষ্ট্য (যেমন Salary) দুটি ক্লাসে ব্যবহার করেন, তবে ডুপ্লিকেট কলাম তৈরি হতে পারে।
- ডেটার পুনঃব্যবহার: উত্তরাধিকারী শ্রেণীগুলোর মধ্যে ডেটা পুনঃব্যবহার করতে না পারার কারণে কোড পুনঃব্যবহারের সুবিধা কমে যেতে পারে।
- ডেটা ব্যবস্থাপনা: একাধিক টেবিল ব্যবস্থাপনা কিছু ক্ষেত্রে জটিল হতে পারে, বিশেষ করে যখন সম্পর্কিত ক্লাসগুলোর মধ্যে তথ্যের সমন্বয় প্রয়োজন।
Table Per Concrete Class (TPC) কৌশলটি কিছু বিশেষ ক্ষেত্রে কার্যকর হতে পারে, তবে এটি সর্বদা সর্বোত্তম পছন্দ নয়। আপনার প্রয়োজনের ভিত্তিতে সঠিক ইনহেরিটেন্স কৌশল নির্বাচন করা উচিত।
NHibernate-এ Inheritance Mapping ব্যবহারের জন্য বিভিন্ন পদ্ধতি রয়েছে, যার মধ্যে Discriminator Column একটি জনপ্রিয় পদ্ধতি। এটি Single Table Inheritance (STI) মডেল অনুসরণ করে, যেখানে সব সাবক্লাসের ডেটা একটি মাত্র টেবিলে সঞ্চিত হয়, এবং Discriminator Column ব্যবহার করে প্রতিটি রেকর্ডের প্রকারভেদ করা হয়।
Discriminator Column কী?
Discriminator Column একটি বিশেষ কলাম যা নির্দেশ করে যে কোন সাবে সাবক্লাসটি একটি নির্দিষ্ট রেকর্ডের সাথে সম্পর্কিত। এটি মূল ক্লাস এবং তার সাবক্লাসের মধ্যে পার্থক্য করতে সাহায্য করে, যখন ডেটাবেসে সবগুলো ক্লাসের ডেটা একসাথে থাকে।
1. Inheritance Mapping এর জন্য Discriminator ব্যবহার করা
এখানে, আমরা একটি উদাহরণ দেখাবো যেখানে একটি Employee ক্লাসের দুটি সাবক্লাস Manager এবং Developer রয়েছে। আমরা Single Table Inheritance পদ্ধতি ব্যবহার করে এগুলোর ডেটা একটি টেবিলে সঞ্চয় করব এবং Discriminator Column এর মাধ্যমে সাবক্লাসের পার্থক্য করব।
ক্লাস গঠন
প্রথমে একটি মূল Employee ক্লাস তৈরি করব এবং তারপরে দুইটি সাবক্লাস তৈরি করব: Manager এবং Developer।
public class Employee
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
public class Manager : Employee
{
public virtual string Department { get; set; }
}
public class Developer : Employee
{
public virtual string ProgrammingLanguage { get; set; }
}
2. hibernate.cfg.xml কনফিগারেশন ফাইল সেটআপ
এখন, hibernate.cfg.xml ফাইলে Inheritance Mapping কনফিগার করব, যাতে Discriminator Column ব্যবহৃত হয়।
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<!-- ডেটাবেস কানেকশন প্রপার্টি -->
<property name="hibernate.connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<property name="hibernate.connection.connection_string">Server=yourserver;Database=yourdb;Integrated Security=True;</property>
<property name="hibernate.dialect">NHibernate.Dialect.MsSql2008Dialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- Inheritance Mapping এর জন্য Discriminator Column ব্যবহার -->
<mapping class="YourNamespace.Employee, YourAssembly"/>
<mapping class="YourNamespace.Manager, YourAssembly"/>
<mapping class="YourNamespace.Developer, YourAssembly"/>
</session-factory>
</hibernate-configuration>
এখানে, Employee, Manager, এবং Developer ক্লাসগুলোকে hibernate.cfg.xml ফাইলে উল্লেখ করা হয়েছে।
3. Entity Mapping (Hbm ফাইল)
এখন, Employee, Manager, এবং Developer ক্লাসের জন্য হাইবারনেট mapping ফাইল তৈরি করব। আমরা Discriminator Column কনফিগার করব যাতে সাবক্লাসের ডেটা পৃথকভাবে চিহ্নিত হয়।
Employee.hbm.xml
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="Employee" table="Employee">
<id name="Id" column="Id">
<generator class="identity"/>
</id>
<property name="Name" column="Name"/>
<!-- Discriminator Column কনফিগার -->
<discriminator column="Discriminator" type="string"/>
</class>
</hibernate-mapping>
Manager.hbm.xml
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<subclass name="Manager" extends="Employee">
<property name="Department" column="Department"/>
</subclass>
</hibernate-mapping>
Developer.hbm.xml
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<subclass name="Developer" extends="Employee">
<property name="ProgrammingLanguage" column="ProgrammingLanguage"/>
</subclass>
</hibernate-mapping>
এখানে, Employee ক্লাসের জন্য একটি Discriminator কলাম সেট করা হয়েছে, যা Manager এবং Developer ক্লাসের মধ্যে পার্থক্য করবে। Discriminator কলামটি ডেটাবেস টেবিলে Discriminator নামে থাকবে এবং তার মান হিসেবে Manager অথবা Developer থাকবে, যা নির্দেশ করবে যে কোন সাবক্লাসের রেকর্ডটি।
4. Database Schema
ডেটাবেসে Employee টেবিলটি কিছুটা এমন দেখতে হবে:
CREATE TABLE Employee (
Id INT PRIMARY KEY IDENTITY,
Name VARCHAR(255),
Discriminator VARCHAR(50),
Department VARCHAR(255), -- Manager জন্য
ProgrammingLanguage VARCHAR(255) -- Developer জন্য
);
এখানে, Discriminator কলামটি Manager অথবা Developer সাবক্লাসের নির্দেশক হিসেবে কাজ করবে। আর Department এবং ProgrammingLanguage কলামগুলো শুধুমাত্র সংশ্লিষ্ট সাবক্লাসের জন্য থাকবে।
5. Entity Save এবং Retrieve করা
এখন, আমরা Session ব্যবহার করে Employee, Manager, এবং Developer Entity সেভ এবং রিট্রিভ করতে পারি।
Entity Save করা:
using NHibernate;
public class EmployeeService
{
public void SaveEmployee()
{
using (ISession session = NHibernateHelper.SessionFactory.OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
var manager = new Manager { Name = "Alice", Department = "HR" };
var developer = new Developer { Name = "Bob", ProgrammingLanguage = "C#" };
session.Save(manager);
session.Save(developer);
transaction.Commit();
}
}
}
}
Entity Retrieve করা:
public void RetrieveEmployees()
{
using (ISession session = NHibernateHelper.SessionFactory.OpenSession())
{
var employees = session.CreateQuery("from Employee").List<Employee>();
foreach (var employee in employees)
{
Console.WriteLine($"Employee: {employee.Name}");
if (employee is Manager manager)
{
Console.WriteLine($"Department: {manager.Department}");
}
else if (employee is Developer developer)
{
Console.WriteLine($"Programming Language: {developer.ProgrammingLanguage}");
}
}
}
}
সারাংশ
- Discriminator Column ব্যবহার করে Single Table Inheritance পদ্ধতিতে Inheritance Mapping করা হয়।
- Discriminator কলামটি সাবক্লাসগুলোর মধ্যে পার্থক্য স্থাপন করে, এবং ডেটাবেসে একটি মাত্র টেবিলেই সব সাবক্লাসের ডেটা রাখা হয়।
- Session ব্যবহার করে Entity সেভ ও রিট্রিভ করার সময় NHibernate স্বয়ংক্রিয়ভাবে Discriminator কলাম ব্যবহার করে সঠিক সাবক্লাস চিহ্নিত করে।
এভাবে, Discriminator Column ব্যবহার করে Inheritance Mapping করতে পারবেন NHibernate-এ।
Read more