আমি আপনার এক্সপার্ট সফটওয়্যার ইঞ্জিনিয়ারিং ট্রেইনার। কোর্স আউটলাইন অনুযায়ী, আমরা এখন Section 15: xUnit testing-এর ভেতরে আছি, তবে এটি PersonsService তৈরির প্রাথমিক ধাপ।

এই লেকচারে আমরা Person এন্টিটি (Entity) এবং এর সাথে সম্পর্কিত DTO (Data Transfer Object) এবং Enum তৈরি করা শিখেছি। চলুন, আজকের লেকচারটি বিস্তারিতভাবে বুঝে নেওয়া যাক।

📝 Lecture Summary (Quick Revision)

ভবিষ্যতে দ্রুত রিভিশন দেওয়ার জন্য সম্পূর্ণ লেকচারের মূল কাজগুলো নিচে লিস্ট আকারে দেওয়া হলো:

  • Domain Model (Person): Entities প্রজেক্টে ডাটাবেস টেবিলের রিপ্রেজেন্টেশন হিসেবে Person ক্লাস তৈরি করা হয়েছে, যেখানে PersonID সহ সব ডাটাবেস প্রপার্টি আছে।
  • Data Hiding Strategy: সরাসরি Domain Model কে Controller বা ক্লায়েন্টের কাছে এক্সপোজ না করে DTO ব্যবহার করার কনসেপ্ট আলোচনা করা হয়েছে।
  • DTO (PersonAddRequest): ServiceContracts প্রজেক্টের DTO ফোল্ডারে PersonAddRequest ক্লাস তৈরি করা হয়েছে। এতে PersonID নেই, কারণ এটি ইউজার ইনপুট দেয় না; সিস্টেম অটোমেটিক জেনারেট করে।
  • Nullable Properties: যে প্রপার্টিগুলো অপশনাল, সেগুলোর ডেটা টাইপের শেষে ? (যেমন: string?, DateTime?) ব্যবহার করে Nullable করা হয়েছে।
  • Enumeration (GenderOptions): জেন্ডার সিলেকশনের জন্য Enums ফোল্ডারে GenderOptions নামের একটি enum তৈরি করা হয়েছে (Male, Female, Other)।
  • Namespace Import: PersonAddRequest DTO-তে GenderOptions ব্যবহারের জন্য enums ফোল্ডারের নেমস্পেস ইমপোর্ট করা হয়েছে।

🧠 Comprehensive Breakdown

এই লেকচারে আমরা Person রিলেটেড ডেটা ম্যানেজমেন্টের জন্য বেসিক মডেল এবং কনট্রাক্ট তৈরি করেছি। চলুন প্রতিটি ধাপ ও কনসেপ্ট বিস্তারিতভাবে বুঝে নিই।

১. Domain Model / Entity Class (Priority: 9/10)

Concept & Why: ডাটাবেসে ডেটা কীভাবে স্টোর হবে তার স্ট্রাকচার ডিফাইন করার জন্য Entities প্রজেক্টে Domain Model তৈরি করা হয়। লেকচারে Person ক্লাস তৈরি করা হয়েছে, যা ভবিষ্যতে Entity Framework-এর মাধ্যমে ডাটাবেস টেবিলে কনভার্ট হবে।

এখানে CountryID (Guid) ব্যবহার করা হয়েছে যা একটি Foreign Key। অর্থাৎ, এই Person কোন দেশের, সেটি দেশের নামের বদলে দেশের ID দিয়ে লিঙ্ক করা থাকবে।

// Entities/Person.cs
public class Person
{
    public Guid PersonID { get; set; }
    public string? PersonName { get; set; }
    public string? Email { get; set; }
    public DateTime? DateOfBirth { get; set; }
    public string? Gender { get; set; }
    public Guid? CountryID { get; set; }
    public string? Address { get; set; }
    public bool ReceiveNewsLetters { get; set; }
}
 

২. Domain Model vs DTO (Data Transfer Object) (Priority: 10/10)

Concept & Why: এটি খুবই গুরুত্বপূর্ণ একটি আর্কিটেকচারাল ডিসিশন।

  • Domain Model (Person): এটি ডাটাবেসের জন্য। এতে এমন অনেক সেনসিটিভ ফিল্ড থাকতে পারে (যেমন: PersonID, CreatedAt, PasswordHash) যা ইউজারকে দেখানো উচিত নয় বা ইউজারের কাছ থেকে ইনপুট হিসেবে নেওয়া উচিত নয়।
  • DTO (PersonAddRequest): এটি ইউজার/ক্লায়েন্টের জন্য। রেজিস্ট্রেশন ফর্মে ইউজার শুধু নাম, ইমেইল, বয়স ইত্যাদি দেয়; সে কখনোই তার নিজের PersonID ইনপুট দেয় না। তাই PersonAddRequest ক্লাসে PersonID রাখা হয়নি।

যেমন লেকচারার ফেসবুকের উদাহরণ দিয়েছেন: ফেসবুক রেজিস্ট্রেশনের সময় শুধু বেসিক কিছু ডেটা (DTO) নেয়, কিন্তু তাদের ডাটাবেসের মেইন টেবিলে (Domain Model) আরও অনেক ফিল্ড থাকে যেগুলো পরে ফিলআপ করা হয়।

// ServiceContracts/DTO/PersonAddRequest.cs
public class PersonAddRequest
{
    public string? PersonName { get; set; }
    public string? Email { get; set; }
    public DateTime? DateOfBirth { get; set; }
    public GenderOptions? Gender { get; set; }
    public Guid? CountryID { get; set; }
    public string? Address { get; set; }
    public bool ReceiveNewsLetters { get; set; }
}
 

৩. Creating and Using Enumeration (Enum) (Priority: 8/10)

Concept & Why: যখন কোনো প্রপার্টির ভ্যালু কয়েকটি নির্দিষ্ট অপশনের মধ্যেই সীমাবদ্ধ থাকতে হয়, তখন string এর বদলে enum ব্যবহার করা সবচেয়ে ভালো প্র্যাকটিস। এতে ভুল বানান বা অবাঞ্ছিত ডেটা ইনসার্ট হওয়া ঠেকানো যায়।

এখানে ইউজারের জেন্ডারের জন্য একটি enum তৈরি করা হয়েছে এবং সেটি DTO-তে ব্যবহার করা হয়েছে।

// ServiceContracts/Enums/GenderOptions.cs
public enum GenderOptions
{
    Male,
    Female,
    Other
}
 

৪. Nullable Types in C# (Priority: 7/10)

Concept & Why: C#-এ string বা DateTime এর মতো টাইপগুলোর শেষে ? (যেমন string?) দিলে সেটি Nullable হয়ে যায়। এর মানে হলো, ফর্মে ইউজার যদি ওই ফিল্ডটি ফাঁকা রাখে, তবে সিস্টেমে সেটি null হিসেবে স্টোর হবে, কোনো ক্র্যাশ করবে না। লেকচারার বলেছেন, যদি কোনো ফিল্ড ম্যান্ডেটরি (Mandatory) হয়, তবে ? দেওয়া যাবে না।


🚀 Modern C# (.NET 8/10) Updates & Smarter Approach

লেকচারের কোডটি সঠিক, তবে মডার্ন C# (C# 9 থেকে C# 12+) ব্যবহার করে DTO তৈরি করার ক্ষেত্রে আমরা আরও স্মার্ট পদ্ধতি ব্যবহার করতে পারি।

1. Using record for DTOs: DTO-গুলো মূলত শুধু ডেটা ক্যারি (Carry) করার জন্য ব্যবহৃত হয়। এগুলোর কোনো নিজস্ব লজিক থাকে না। তাই মডার্ন C#-এ ক্লাসের বদলে record ব্যবহার করা অনেক বেশি স্ট্যান্ডার্ড এবং পারফরম্যান্স-বান্ধব।

Modern PersonAddRequest Implementation:

// Record দিয়ে তৈরি করা DTO অনেক বেশি ক্লিন এবং Value Equality সাপোর্ট করে
public record PersonAddRequest
{
    public string? PersonName { get; init; }
    public string? Email { get; init; }
    public DateTime? DateOfBirth { get; init; }
    public GenderOptions? Gender { get; init; }
    public Guid? CountryID { get; init; }
    public string? Address { get; init; }
    public bool ReceiveNewsLetters { get; init; }
}
 

(এখানে set এর বদলে init ব্যবহার করা হয়েছে, যার মানে হলো অবজেক্ট তৈরি হওয়ার পর আর ডেটা পরিবর্তন করা যাবে না। এটি Immutable DTO তৈরি করার বেস্ট প্র্যাকটিস)।


🏆 Best Practices (Entity & DTO Design)

  1. Never Expose Entities: ডাটাবেসের Entity ক্লাসগুলোকে কখনোই Controller বা API Response-এ সরাসরি ব্যবহার করবেন না। সব সময় Entity থেকে DTO তে ম্যাপ করে তারপর ক্লায়েন্টকে রেসপন্স দিন।
  2. Use Data Annotations / Fluent API Validation: DTO এর প্রপার্টিগুলোর ওপরে Data Annotations (যেমন [Required], [EmailAddress]) ব্যবহার করা উচিত, যাতে Controller-এ আসার আগেই ডেটা ভ্যালিডেট হয়ে যায়। (সম্ভবত লেকচারার এটি পরবর্তী সেকশনগুলোতে দেখাবেন)।
  3. Use Enums for Fixed Categories: Status (Active, Inactive), Roles (Admin, User), Gender ইত্যাদির জন্য সবসময় enum ব্যবহার করুন, string নয়।