হ্যালো হাসিব! এই লেকচারটিতে আমরা থিওরি থেকে প্র্যাকটিক্যালে চলে এসেছি। আগের লেকচারে বানানো ইন্টারফেসগুলোর (Contracts) আসল ইমপ্লিমেন্টেশন করা হয়েছে এখানে।

Clean Architecture-এর অন্যতম প্রধান রুল হলো Separation of Concerns। “Chatrabash” এর মতো স্কেলেবল SaaS প্রজেক্টে এই লেকচারের কনসেপ্টটি খুবই কাজে দেবে। চলো লেকচারটির একটি কুইক সামারি এবং বিস্তারিত পোস্টমর্টেম করে ফেলি।

📝 Lecture Summary at a Glance

  • New Project Setup: Repositories নামে একটি নতুন Class Library প্রজেক্ট তৈরি করা হয়েছে, যা Entities এবং RepositoryContracts এর ওপর ডিপেন্ড করে।
  • Dependency Injection: রিপোজিটরির ভেতরে ডাটাবেসের সাথে কানেক্ট করার জন্য কনস্ট্রাক্টরের মাধ্যমে DbContext ইনজেক্ট করা হয়েছে।
  • The Golden Rule: রিপোজিটরিতে কোনো বিজনেস লজিক বা ভ্যালিডেশন থাকবে না। এটি ব্লাইন্ডলি শুধু ডাটাবেসে ডাটা ইনসার্ট বা ফেচ করবে।
  • EF Core Methods: ডাটাবেস অপারেশনের জন্য EF Core-এর বিল্ট-ইন অ্যাসিনক্রোনাস মেথডগুলো (ToListAsync, FirstOrDefaultAsync, SaveChangesAsync) ব্যবহার করা হয়েছে।

🧠 Comprehensive Breakdown & Deep Dive

১. The “No Business Logic” Rule [Importance: 10/10]

  • The “Why”: এটি রিপোজিটরি প্যাটার্নের সবচেয়ে গুরুত্বপূর্ণ পয়েন্ট। লেকচারার বারবার বলেছেন যে, একটি নতুন Country অ্যাড করার আগে তার নাম ঠিক আছে কিনা বা ডাটাবেসে ডুপ্লিকেট নাম আছে কিনা—এই চেকিংগুলো (Validation/Business Logic) রিপোজিটরি করবে না।
  • Who does it? ভ্যালিডেশনের কাজ হলো Service Layer-এর। Service ভ্যালিডেট করে কনফার্ম হওয়ার পর রিপোজিটরিকে শুধু বলবে, “এই নাও ডাটা, ডাটাবেসে সেভ করো।” রিপোজিটরি শুধু ডাটাবেস চেনে, বিজনেস রুলস নয়।

২. Injecting DbContext [Importance: 9/10]

  • The “Why”: রিপোজিটরিকে তো ডাটাবেসের সাথে কথা বলতে হবে। ASP.NET Core-এর IoC (Inversion of Control) কন্টেইনার থেকে DbContext রিসিভ করার জন্য কনস্ট্রাক্টর ইনজেকশন ব্যবহার করা হয়।

💻 Code Implementation (CountriesRepository.cs):

using Entities;
using Microsoft.EntityFrameworkCore;
using RepositoryContracts;
 
public class CountriesRepository : ICountriesRepository
{
    private readonly ApplicationDbContext _db;
 
    // Constructor Injection
    public CountriesRepository(ApplicationDbContext db)
    {
        _db = db;
    }
    
    // ... methods ...
}
 

৩. Implementing CRUD Operations (EF Core) [Importance: 10/10]

  • The “Why”: EF Core-এর পাওয়ার ব্যবহার করে খুব সহজেই ডাটাবেস অপারেশনগুলো করা যায়। যেহেতু আমরা সবকিছু async করছি, তাই মেথডগুলোতে await ব্যবহার করা মাস্ট।

💻 Code Implementation:

Add Operation:

public async Task<Country> AddCountry(Country country)
{
    _db.Countries.Add(country);
    await _db.SaveChangesAsync(); // ডাটাবেসে সেভ করা
    return country;
}
 

Read Operations:

public async Task<List<Country>> GetAllCountries()
{
    return await _db.Countries.ToListAsync();
}
 
public async Task<Country?> GetCountryByCountryName(string countryName)
{
    // FirstOrDefaultAsync ব্যবহার করে নির্দিষ্ট ডাটা খুঁজে বের করা
    return await _db.Countries.FirstOrDefaultAsync(temp => temp.CountryName == countryName);
}
 

🚀 Modern Clean Architecture Notes

১. Where does this fit in Clean Architecture? আমরা যে প্রজেক্টগুলো বানাচ্ছি, ক্লিন আর্কিটেকচারের ভাষায় সেগুলোর একটি নির্দিষ্ট নাম আছে:

  • Entities + RepositoryContracts = Core / Domain Layer (এটি প্রজেক্টের হার্ট, এটি কারো ওপর ডিপেন্ড করে না)।
  • Services = Application Layer (এখানে বিজনেস লজিক থাকে)।
  • Repositories = Infrastructure Layer (এখানে ডাটাবেস, থার্ড-পার্টি API বা এক্সটার্নাল প্যাকেজের কাজ থাকে)।

২. Performance Tip (Tracking vs No-Tracking): লেকচারার GetAllCountries মেথডে সরাসরি .ToListAsync() ব্যবহার করেছেন। তুমি যখন শুধু ডাটা রিড করবে (অর্থাৎ ডাটাবেসে কোনো আপডেট বা ডিলিট করবে না), তখন .AsNoTracking() ব্যবহার করাটা বেস্ট প্র্যাকটিস। এতে EF Core ডাটাগুলোকে মেমোরিতে ট্র্যাক করে না, ফলে কুয়েরি অনেক ফাস্ট হয় এবং র‍্যাম কম টানে।

public async Task<List<Country>> GetAllCountries()
{
    // ফাস্টার পারফরম্যান্সের জন্য AsNoTracking
    return await _db.Countries.AsNoTracking().ToListAsync(); 
}
 

পরবর্তী লেকচারে সম্ভবত PersonsRepository এর ইমপ্লিমেন্টেশন দেখানো হবে, যেখানে ডাইনামিক ফিল্টারিংয়ের (Expression<Func<T, bool>>) প্র্যাকটিক্যাল ব্যবহার দেখা যাবে। তুমি কি পরের ট্রান্সক্রিপ্টটি দিতে চাও?