হ্যালো হাসিব! এই লেকচারে আমরা CRUD অপারেশনের “U” অর্থাৎ Update (Edit) ফাংশনালিটি ইমপ্লিমেন্ট করা শিখেছি। Create এবং Edit ভিউয়ের কাজ প্রায় একই রকম, শুধু পার্থক্য হলো Edit পেজে ঢোকার সময় আগে থেকেই ইউজারের ডাটা ফিল্ডগুলোতে ফিল-আপ করা থাকে এবং সাবমিট করলে নতুন ডাটা তৈরি হওয়ার বদলে আগের ডাটা আপডেট হয়।
চলো প্রথমে লেকচারটির একটি কুইক সামারি দেখে নিই।
📌 Quick Summary for Revision
- Reusing UI:
Create.cshtmlকপি করেEdit.cshtmlতৈরি করা এবং শুধু টাইটেল ও বাটনের টেক্সট (“Update”) পরিবর্তন করা। - Model Change: ভিউয়ের
@modelহিসেবেPersonAddRequestএর বদলেPersonUpdateRequestব্যবহার করা। - Dynamic Edit Link:
Index.cshtml-এ প্রতিটি সারির পাশেasp-route-personIDট্যাগ হেল্পার ব্যবহার করে এডিট পেজের ডাইনামিক লিংক তৈরি করা। - GET Action Method: Controller-এ
Edit(GET) মেথড তৈরি করা, যা ID রিসিভ করে সার্ভিস থেকে ইউজারের এক্সিস্টিং ডাটা এনে ভিউতে পাঠায়। - Hidden Field:
Edit.cshtmlফর্মে<input type="hidden" asp-for="PersonID" />অ্যাড করা, যাতে ফর্ম সাবমিট করার সময় ID-টি হারিয়ে না যায়। - POST Action Method: ফর্ম সাবমিট রিসিভ করার জন্য
Edit(POST) মেথড তৈরি করা। এখানে ডাটাবেসে ID এক্সিস্ট করে কি না তা ভেরিফাই করে,ModelStateচেক করে ডাটা আপডেট করা এবংIndexপেজে রিডাইরেক্ট করা।
🚀 Comprehensive Breakdown & The “Why”
নিচে লেকচারের প্রতিটি কনসেপ্ট বিস্তারিত এবং কারণসহ এক্সপ্লেইন করা হলো:
১. Dynamic Edit Link তৈরি করা (Index.cshtml) [Priority: 10/10]
The “Why”: ইউজারের লিস্ট থেকে নির্দিষ্ট কোনো ইউজারকে এডিট করতে চাইলে, লিংকের মাধ্যমে সেই ইউজারের PersonID Controller-এ পাঠাতে হবে। asp-route-{parameter} ট্যাগ হেল্পারটি ডাইনামিক্যালি URL তৈরি করে (যেমন: /persons/edit/123)।
Implementation:
<td>
<a asp-controller="Persons"
asp-action="Edit"
asp-route-personID="@person.PersonID">Edit</a>
</td>
২. GET Action Method (ভিউ লোড করা) [Priority: 10/10]
The “Why”: যখন ইউজার “Edit” লিংকে ক্লিক করে, তখন এটি একটি GET রিকোয়েস্ট। এই মেথডের কাজ হলো URL থেকে personID রিসিভ করা, ডাটাবেস থেকে ওই ইউজারের ইনফরমেশন খুঁজে বের করা এবং ড্রপডাউনের জন্য Countries-এর লিস্টসহ ভিউতে পাঠানো। যদি কেউ ভুল ID দিয়ে রিকোয়েস্ট করে (Null), তবে তাকে আবার Index পেজে ব্যাক করিয়ে দেওয়া।
Implementation:
[Route("[action]/{personID}")] // Route Token এবং Parameter
[HttpGet]
public IActionResult Edit(Guid personID)
{
// ১. ID দিয়ে পার্সন খোঁজা
PersonResponse? personResponse = _personsService.GetPersonByPersonID(personID);
// ২. যদি পার্সন না পাওয়া যায়, তবে Index-এ রিডাইরেক্ট করা
if (personResponse == null)
{
return RedirectToAction("Index");
}
// ৩. PersonResponse কে PersonUpdateRequest এ কনভার্ট করা
PersonUpdateRequest personUpdateRequest = personResponse.ToPersonUpdateRequest();
// ৪. ড্রপডাউনের জন্য Countries লোড করা
ViewBag.Countries = _countriesService.GetAllCountries().Select(temp =>
new SelectListItem() { Text = temp.CountryName, Value = temp.CountryID.ToString() }
);
// ৫. এক্সিস্টিং ডাটা ভিউতে পাঠানো (Tag Helper অটোমেটিক ভ্যালুগুলো ইনপুটে বসিয়ে দেবে)
return View(personUpdateRequest);
}
৩. Edit View এবং Hidden Field [Priority: 10/10]
The “Why”: যখন আমরা ফর্ম সাবমিট করবো (POST), তখন কোন ইউজারের ডাটা আপডেট হচ্ছে, তা সার্ভারকে বোঝাতে PersonID পাঠানো বাধ্যতামূলক। কিন্তু আমরা চাই না ইউজার তার ID দেখুক বা পরিবর্তন করুক। তাই <input type="hidden"> ব্যবহার করা হয়। এটি ফর্মে থাকে এবং সাবমিটও হয়, কিন্তু ইউজার চোখে দেখতে পারে না।
Implementation (Edit.cshtml):
@model ServiceContracts.DTO.PersonUpdateRequest
<form asp-controller="Persons" asp-action="Edit" 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" /></div>
</div>
<button class="button button-green-back">Update</button>
</form>
৪. POST Action Method (ডাটা আপডেট করা) [Priority: 10/10]
The “Why”: ইউজার ফর্মে এডিট করে “Update” বাটনে ক্লিক করলে ডাটা এই মেথডে আসবে। এখানে সরাসরি ডাটাবেসে সেভ না করে, আগে চেক করতে হয় যে URL-এর ID এবং ফর্মের ভেতরের ID ঠিক আছে কি না এবং ওই ইউজার আসলেই সিস্টেমে এক্সিস্ট করে কি না (সিকিউরিটির জন্য)। সব ঠিক থাকলে আপডেট করে PRG (Post-Redirect-Get) প্যাটার্ন ফলো করে Index পেজে পাঠিয়ে দেওয়া হয়।
Implementation:
[Route("[action]/{personID}")]
[HttpPost]
public IActionResult Edit(PersonUpdateRequest personUpdateRequest)
{
// ১. এক্সিস্টিং পার্সন ভেরিফাই করা (Don't trust the client)
PersonResponse? personResponse = _personsService.GetPersonByPersonID(personUpdateRequest.PersonID);
if (personResponse == null)
{
return RedirectToAction("Index");
}
// ২. Model Validation চেক করা
if (ModelState.IsValid)
{
// ৩. ভ্যালিড হলে আপডেট করা এবং রিডাইরেক্ট করা
_personsService.UpdatePerson(personUpdateRequest);
return RedirectToAction("Index");
}
else
{
// ৪. ইনভ্যালিড হলে ড্রপডাউনের ডাটা আবার পাঠিয়ে ফর্মটি রিলোড করা
ViewBag.Countries = _countriesService.GetAllCountries().Select(temp =>
new SelectListItem() { Text = temp.CountryName, Value = temp.CountryID.ToString() }
);
// Error messages ViewBag-এ পাঠানোর দরকার নেই যদি তুমি Tag Helpers ব্যবহার করো
return View(personUpdateRequest);
}
}
🆕 .NET 10 & Modern Approaches (AutoMapper)
লেকচারে PersonResponse.ToPersonUpdateRequest() নামের একটি কাস্টম মেথড ব্যবহার করে ডাটা কনভার্ট করা হয়েছে। রিয়েল-লাইফ এবং মডার্ন .NET প্রোজেক্টে এক অবজেক্ট থেকে আরেক অবজেক্টে ডাটা ম্যাপ (Copy) করার জন্য AutoMapper বা Mapster এর মতো লাইব্রেরি ব্যবহার করা হয়, যা কোড অনেক কমিয়ে দেয়।
Modern Approach with AutoMapper:
// AutoMapper ব্যবহার করলে কনভার্সন এক লাইনে হয়ে যায়
PersonUpdateRequest updateRequest = _mapper.Map<PersonUpdateRequest>(personResponse);
⌨️ IDE Shortcuts
- Duplicate a File/Folder:
- Visual Studio: সলিউশন এক্সপ্লোরারে ফাইলটি সিলেক্ট করে
Ctrl+C, তারপর ফোল্ডারেCtrl+VচাপলেFileName - Copyতৈরি হয়। এরপরF2চেপে রিনেম করা যায়। - Visual Studio Code: ফাইলে রাইট ক্লিক করে
Copy, তারপরPaste(অথবাCtrl+C,Ctrl+V)।
💡 Best Practices (Edit/Update Operations)
১. Always Use Hidden Field for Primary Key: এডিট ফর্মে প্রাইমারি কি (ID) সবসময় Hidden ফিল্ডে রাখতে হবে, নাহলে POST অ্যাকশনে তা Empty/Null হয়ে যাবে।
২. Double Validation: ক্লায়েন্ট-সাইডে ভ্যালিডেশন থাকলেও POST মেথডের ভেতরে পুনরায় ডাটাবেস চেক করা (ইউজার আসলেই আছে কি না) বাধ্যতামূলক। হ্যাকাররা Hidden ফিল্ডের ভ্যালু ব্রাউজার থেকে পরিবর্তন করে অন্য ইউজারের ডাটা আপডেট করার চেষ্টা করতে পারে।
৩. Repopulate Dropdowns on Failure: ModelState.IsValid ফেইল করলে অবশ্যই ড্রপডাউনের ডাটা পুনরায় লোড করে পাঠাতে হবে, নাহলে ভিউ রেন্ডার হওয়ার সময় অ্যাপ্লিকেশন ক্র্যাশ করবে।
CRUD-এর মধ্যে আমাদের Read, Create এবং Update শেষ! এরপর কি আমরা সর্বশেষ অংশ অর্থাৎ Delete View-এর লেকচারে মুভ করবো?