হ্যালো হাসিব! আমরা ডাটাবেসের কনস্ট্রেইন্ট (Constraints) নিয়ে কথা বলবো এই লেকচারে।
ডাটাবেস ডিজাইনে শুধু কলাম অ্যাড করলেই হয় না, সেখানে ভুল বা ডুপ্লিকেট ডাটা যেন ঢুকতে না পারে, তার জন্য রুলস সেট করতে হয়। এই রুলসগুলোকেই Constraints বলা হয়।
চলো লেকচারটির একটি কুইক সামারি এবং বিস্তারিত পোস্টমর্টেম করে ফেলি।
📝 Lecture Summary at a Glance
- Constraints Overview: ডাটাবেসে ডাটার শুদ্ধতা (Data Integrity) বজায় রাখার জন্য বিভিন্ন রুলস (Primary Key, Not Null, Unique, Check) অ্যাপ্লাই করা হয়।
- Unique Constraint: কোনো কলামে যেন ডুপ্লিকেট ভ্যালু না বসে, সেজন্য Fluent API-তে
HasIndex().IsUnique()ব্যবহার করা হয়। - Check Constraint: কোনো কলামের ভ্যালুর ওপর স্পেসিফিক লজিক (যেমন: লেন্থ অবশ্যই ৮ ক্যারেক্টার হতে হবে) চেক করার জন্য
HasCheckConstraint()ব্যবহার করা হয়। - The Invalid Column Error: Check Constraint-এ কলামের নাম লেখার সময় Model Class-এর প্রপার্টি নাম (
TIN) লিখলে এরর আসবে। অবশ্যই Fluent API-তে দেওয়া ডাটাবেসের রিয়েল কলাম নাম (TaxIdentificationNumber) লিখতে হবে।
🧠 Comprehensive Breakdown & Deep Dive
১. Unique Constraint [Importance: 9/10]
- The “Why”: তোমার ইউজারদের ইমেইল বা NID নম্বর কখনোই ডুপ্লিকেট হওয়া উচিত নয়। ডাটাবেস লেভেলে এই ডুপ্লিকেশন ঠেকানোর জন্যই Unique Constraint ব্যবহার করা হয়।
- The Caveat: লেকচারার এটি কমেন্ট করে রেখেছেন, কারণ আগের লেকচারে আমরা TIN কলামে একটি Default Value সেট করেছিলাম (
ABC12345)। এখন যদি তুমি Unique Constraint দাও, তাহলে ডাটাবেসে নতুন ইউজার ইনসার্ট করার সময় সবার TIN ডিফল্টভাবেABC12345হতে চাইবে, আর তখন SQL Server ডুপ্লিকেট ডাটার কারণে এরর থ্রো করবে!
💻 Code Implementation:
যদি তোমার অন্য কোনো কলাম (যেমন: Email) ইউনিক করতে হয়, তবে এভাবে করবে:
modelBuilder.Entity<Person>()
.HasIndex(p => p.Email) // প্রথমে ইনডেক্স তৈরি করা
.IsUnique(); // তারপর তাকে ইউনিক ডিক্লেয়ার করা
২. Check Constraint [Importance: 8/10]
- The “Why”: ধরো তুমি চাও ইউজারদের বয়স যেন ১৮ এর নিচে না হয়, বা TIN নম্বর যেন ঠিক ৮ ক্যারেক্টারের হয়। এই ধরনের কাস্টম লজিক সরাসরি ডাটাবেস টেবিলে বসিয়ে দেওয়ার জন্য Check Constraint ব্যবহার করা হয়। এতে কেউ সরাসরি ডাটাবেসে ভুল ডাটা পুশ করতে চাইলেও পারবে না।
💻 Code Implementation:
modelBuilder.Entity<Person>()
.HasCheckConstraint("CHK_TIN_Length", "len([TaxIdentificationNumber]) = 8");
(এখানে লেকচারার প্রথম প্যারামিটারে কনস্ট্রেইন্টের নাম এবং দ্বিতীয় প্যারামিটারে রিয়েল SQL লজিক দিয়েছেন।)
৩. The “Invalid Column” Error Explained [Importance: 10/10]
- The “Why”: লেকচারার যখন প্রথমবার মাইগ্রেশন আপডেট করলেন, তখন SQL Server এরর দিল। কারণ তিনি Check Constraint-এর ভেতরে
len([TIN]) = 8লিখেছিলেন। - Reason: আমরা আগের লেকচারেই Fluent API দিয়ে বলে দিয়েছি যে
TINপ্রপার্টির নাম ডাটাবেসে হবেTaxIdentificationNumber। SQL Server তোমার C# এরTINপ্রপার্টি চেনে না, সে তার নিজের কলামের নাম চেনে। তাই ব্র্যাকেটের ভেতরে রিয়েল কলামের নামটাই দিতে হবে।
🚀 Modern Entity Framework Core Best Practices
১. Validation in Code vs Database: Check Constraint ডাটাবেসের জন্য ভালো, তবে ক্লিন আর্কিটেকচারে (Clean Architecture) এই ধরনের ভ্যালিডেশন (যেমন TIN ৮ ক্যারেক্টার হওয়া) সাধারণত C# Code (Domain Layer বা DTO Validation)-এ রাখা হয় (যেমন FluentValidation ব্যবহার করে)। কারণ ডাটাবেস থেকে এরর থ্রো হলে সেটি ইউজার-ফ্রেন্ডলি মেসেজে কনভার্ট করা ঝামেলার। ডাটাবেসে শুধু লাস্ট-লাইন-অফ-ডিফেন্স হিসেবে কনস্ট্রেইন্ট রাখা উচিত।
২. Table and Column Names in Check Constraints:
হার্ডকোড করে স্ট্রিংয়ের ভেতরে কলামের নাম না লিখে nameof বা EF Core-এর বিল্ট-ইন ফাংশন ব্যবহার করা বেস্ট প্র্যাকটিস, যাতে ভবিষ্যতে কলামের নাম চেঞ্জ হলে রানটাইম এরর না আসে।
// ❌ Old Error-Prone Style:
.HasCheckConstraint("CHK_TIN", "len([TaxIdentificationNumber]) = 8")
// ✅ Smart Style (যদি প্রপার্টি এবং কলাম নাম সেম থাকে):
.HasCheckConstraint($"CHK_{nameof(Person.TIN)}", $"len([{nameof(Person.TIN)}]) = 8")
৩. VS Code / CLI Workflow Reminder: যেকোনো কনস্ট্রেইন্ট অ্যাড করার পর লিনাক্স টার্মিনালে এই কমান্ডগুলো ভুলবে না:
dotnet ef migrations add AddTINCheckConstraint --project Entities --startup-project CrudExample
dotnet ef database update --project Entities --startup-project CrudExample
পরবর্তী লেকচারে EF Core-এর সবচেয়ে পাওয়ারফুল এবং ট্রিকি পার্ট Table Relations (Foreign Keys & Navigation Properties) নিয়ে আলোচনা করা হবে। তুমি রেডি হলে সেই ট্রান্সক্রিপ্টটি দিতে পারো!