হ্যালো হাসিব! এই লেকচারে আমরা আমাদের CRUD অপারেশনের সর্বশেষ অংশ অর্থাৎ “Delete” ফাংশনালিটি ইমপ্লিমেন্ট করা শিখেছি। এই অংশটি Edit-এর মতোই, তবে এখানে ইউজার ডাটা পরিবর্তন করতে পারে না (Read-Only) এবং সাবমিট বাটনে ক্লিক করলে ডাটাবেস (বা ইন-মেমোরি কালেকশন) থেকে সেই ইউজারকে মুছে ফেলা হয়।

চলো প্রথমে লেকচারটির একটি কুইক সামারি দেখে নিই।

📌 Quick Summary for Revision

  • Reusing UI: Edit.cshtml কপি করে Delete.cshtml তৈরি করা এবং শুধুমাত্র Person Name ও Email রেখে বাকি ইনপুটগুলো মুছে ফেলা।
  • Read-Only Fields: ফর্মের ইনপুটগুলোতে disabled="disabled" অ্যাট্রিবিউট ব্যবহার করা, যাতে ইউজার ডাটা পরিবর্তন করতে না পারে।
  • Hidden Field: এডিটের মতোই ফর্মে <input type="hidden" asp-for="PersonID" /> রাখা, যেন POST করার সময় ID সাবমিট হয়।
  • GET Action Method: Controller-এ Delete (GET) মেথড তৈরি করে নির্দিষ্ট Person-এর ডাটা এনে ভিউতে দেখানো।
  • POST Action Method: সাবমিটের পর Delete (POST) মেথড তৈরি করে _personsService.DeletePerson() কল করা এবং ডাটা রিমুভ করে Index পেজে রিডাইরেক্ট করা।
  • Bug Fix (Edit): আগের লেকচারের Edit (POST) মেথডে ভ্যালিডেশন ফেইল হলে View(personUpdateRequest) রিটার্ন করার বিষয়টি ফিক্স করা, যাতে ফর্ম রিলোড হওয়ার সময় আগের ডাটাগুলো মুছে না যায়।

🚀 Comprehensive Breakdown & The “Why”

নিচে লেকচারের প্রতিটি কনসেপ্ট বিস্তারিত এবং কারণসহ এক্সপ্লেইন করা হলো:

১. Delete View তৈরি এবং Disabled Fields [Priority: 10/10]

The “Why”: ডিলিট করার আগে ইউজারকে দেখানো উচিত সে কাকে ডিলিট করছে। কিন্তু সে যেন এই ফর্মে কোনো কিছু এডিট করতে না পারে, তাই ফর্ম ফিল্ডগুলোকে disabled করে দেওয়া হয়। disabled ফিল্ডের ডাটা ফর্ম সাবমিটের সময় ব্রাউজার সার্ভারে পাঠায় না। তাই সার্ভারে শুধু ID পাঠানোর জন্য একটি Hidden ফিল্ড রাখা বাধ্যতামূলক।

Implementation (Delete.cshtml):

@model ServiceContracts.DTO.PersonResponse
 
<h3>Are you sure to delete?</h3>
 
<form asp-controller="Persons" asp-action="Delete" method="post">
    <input type="hidden" asp-for="PersonID" />
    
    <div class="form-field flex">
        <div class="w-25"><label asp-for="PersonName"></label></div>
        <div class="flex-1"><input asp-for="PersonName" class="form-input" disabled="disabled" /></div>
    </div>
    
    <button class="button button-red-back">Delete</button>
</form>
 

২. GET Action Method (ভিউ লোড করা) [Priority: 10/10]

The “Why”: ইউজার “Delete” লিংকে ক্লিক করলে ഈ মেথডটি কল হয়। এটি URL থেকে ID নিয়ে ইউজারের ডাটাবেস থেকে ইনফরমেশন নিয়ে আসে এবং Delete.cshtml ভিউতে দেখায়।

Implementation:

[Route("[action]/{personID}")]
[HttpGet]
public IActionResult Delete(Guid personID)
{
    PersonResponse? personResponse = _personsService.GetPersonByPersonID(personID);
    if (personResponse == null)
    {
        return RedirectToAction("Index");
    }
 
    return View(personResponse); // Delete View-তে ডাটা পাঠানো হচ্ছে
}
 

৩. POST Action Method (ডাটা ডিলিট করা) [Priority: 10/10]

The “Why”: ইউজার “Delete” বাটনে ক্লিক করলে POST রিকোয়েস্ট আসে। যেহেতু ইনপুট ফিল্ডগুলো disabled ছিল, তাই ফর্ম থেকে শুধু PersonID (Hidden Field থেকে) সার্ভারে আসবে। লজিক্যাল নোট: এখানে প্যারামিটার হিসেবে শুধু Guid personID নেওয়া যেত, কিন্তু যেহেতু Delete(Guid personID) নামের একটি GET মেথড আগে থেকেই আছে, তাই Method Overloading-এর কনফ্লিক্ট এড়ানোর জন্য প্যারামিটার হিসেবে একটি অবজেক্ট (PersonUpdateRequest) রিসিভ করা হয়েছে, যার ভেতর থেকে আমরা ID-টা এক্সট্রাক্ট করে নেবো।

Implementation:

[Route("[action]/{personID}")]
[HttpPost]
public IActionResult Delete(PersonUpdateRequest personUpdateRequest)
{
    // ১. এক্সিস্টিং পার্সন ভেরিফাই করা
    PersonResponse? personResponse = _personsService.GetPersonByPersonID(personUpdateRequest.PersonID);
    if (personResponse == null)
    {
        return RedirectToAction("Index");
    }
 
    // ২. ডিলিট করা
    _personsService.DeletePerson(personUpdateRequest.PersonID);
    
    // ৩. ডিলিট শেষে লিস্টে ফেরত পাঠানো
    return RedirectToAction("Index");
}
 

৪. Edit Method Bug Fix [Priority: 8/10]

The “Why”: আগের লেকচারে Edit (POST) মেথডে যদি ModelState.IsValid ফলস হতো, তবে ফর্ম রিলোড করার সময় আমরা শুধু return View() কল করছিলাম। এতে ফর্ম ফাঁকা হয়ে যাচ্ছিল। এর সমাধান হিসেবে ভিউতে আবার ইউজারের ইনপুট করা অবজেক্টটি পাস করা হয়েছে।

Implementation (Edit POST):

if (!ModelState.IsValid)
{
    // Dropdown ডাটা লোড করা...
    // ইউজারের আগের ইনপুটগুলো (personUpdateRequest) আবার ভিউতে ফেরত পাঠানো
    return View(personUpdateRequest); 
}
 

🆕 .NET 10 & Modern Approaches (Delete Confirmation)

লেকচারে ডিলিট করার জন্য একটি আলাদা পেজ (Delete View) তৈরি করা হয়েছে। এটি ট্র্যাডিশনাল MVC অ্যাপ্রোচ। Modern Workflow (AJAX & Modals): আজকালকার প্রোডাকশন অ্যাপ্লিকেশনগুলোতে ডিলিটের জন্য সাধারণত আলাদা পেজে নেওয়া হয় না। এর বদলে ইউজারের লিস্টেই “Delete” বাটনে ক্লিক করলে JavaScript (SweetAlert / Bootstrap Modal) দিয়ে একটি পপআপ আসে “Are you sure?”. ইউজার “Yes” দিলে ব্যাকগ্রাউন্ডে AJAX দিয়ে API কল করে ডাটা ডিলিট করা হয় এবং পেজ রিলোড ছাড়াই টেবিল থেকে Row-টি রিমুভ করে দেওয়া হয় (যা ইউজার এক্সপেরিয়েন্স অনেক ভালো করে)।


⌨️ IDE Shortcuts

  • Method Overloading Conflict Check:
  • কোড লেখার সময় যদি দুটি মেথডের সিগনেচার সেম হয়ে যায়, ভিজ্যুয়াল স্টুডিওতে সাথে সাথে মেথডের নামের নিচে Red Squiggly Line (লাল দাগ) চলে আসে। ওই দাগের ওপর মাউস নিলে এররটি ডিটেইলে দেখা যায়।

💡 Best Practices (Delete Operations)

১. Soft Delete vs Hard Delete: এই লেকচারে ডাটা পারমানেন্টলি রিমুভ (Hard Delete) করা হয়েছে। কিন্তু রিয়েল-ওয়ার্ল্ড প্রজেক্টে সাধারণত Soft Delete করা হয় (ডাটাবেসে IsDeleted = true করে রাখা হয়, যাতে ভুল করে ডিলিট হলে রিকভার করা যায়)। ২. Disabled vs Readonly: disabled ইনপুটের ডাটা ফর্ম সাবমিটে যায় না। যদি এমন কোনো ফিল্ড থাকে যা ইউজার এডিট করতে পারবে না কিন্তু ফর্ম সাবমিটের সময় ডাটা সার্ভারে যেতে হবে, তবে disabled এর বদলে readonly="readonly" ব্যবহার করতে হবে।

অভিনন্দন! এই লেকচারের মাধ্যমে আমরা আমাদের সম্পূর্ণ CRUD (Create, Read, Update, Delete) অপারেশন শেষ করে ফেললাম। লেকচারার বলেছেন, যেহেতু আমাদের ডাটাগুলো এখন “In-memory” (লিস্টে) সেভ হচ্ছে, তাই সার্ভার রিস্টার্ট দিলে সব ডিলিট হয়ে যাবে। আগামী সেকশন থেকে আমরা Entity Framework Core ব্যবহার করে ডাটাগুলো আসল ডাটাবেসে (Permanent Storage) সেভ করা শিখবো।

CRUD এর পুরো ফ্লো নিয়ে তোমার কি কোনো প্রশ্ন বা কনফিউশন আছে?