رفع ارور The property Code is part of the objec
در حین کار بر روی پروژه که با تکنولوژی Codefirst آن را ایجاد کرده بودیم به ارور The property 'Code' is part of the object's key information and cannot be modified در Entityframework برخورد نمودم. جریان از این قرار بود که نیاز به این داشتیم که از رکورد موجود در دیتابیس یک کپی تهیه کنیم و پس از تغییر مقدار CODE آن رکورد مجددا آنرا در پایگاه داده درج کنیم. نکته مهم این بود که این جدول در حقیقت یک جدول MASTER بود و دارای یک سری جدول Detail بود که به هم از طریق فیلد Code متصل بودند و نیاز بود که در زمان واکشی این رکود آن مقادیر داخلب فیلد های Detail هم واکشی و در نهایت پس از تغییر کد مجددا کپی شوند و رکورد قبلی پاک شود. ساختار کد نوشته شده به شکل زیر بود.
public void CreateCustomer(int _CustomerNewCode, int PrevCode)
{
using (DbContextTransaction transaction = _context.Database.BeginTransaction())
{
try
{
Entity.CustomerServiceSupport.Customer agnt = _context.Customers.FirstOrDefault(n => n.Code == PrevCode);
agnt.Code = _CustomerNewCode;
agnt.IsRequestCustomer = false;
foreach (var itm in agnt.CustomerFiles)
{
itm.Customer_Code = _CustomerNewCode;
}
foreach (var itm in agnt.CustomerPlaces)
{
itm.Customer_Code = _CustomerNewCode;
}
foreach (var itm in agnt.CustomerBankAccounts)
{
itm.Customer_Code = _CustomerNewCode;
}
_context.Customers.Add(agnt);
_context.SaveChanges();
Entity.CustomerServiceSupport.Customer agnt1 = _context.Customers.FirstOrDefault(n => n.Code == PrevCode);
_context.Customers.Remove(agnt1);
_context.SaveChanges();
transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
MessageBox.Show(ex.Message);
}
}
}
یکی از مشکلات دیگری که وجود داشت این بود که گاها رکوردهای مرتبط به این جدول MASTER کپی و منتقل نمی شدند. برای رفع این مشکل جدولهای Detail را نیز با دستور Include به جدول اصلی ارتباط دادم. برای اینکه انسجام دستورات حفظ شود و همه دستورات به درستی انجام شود از DbContextTransaction هم استفاده کردم. دلیل این پیغام هم این بود که رشته اتصال با پایگاه داده در کلاس EF برقرار می ماند و در صورت اعمال هر گونه تغییر ، اتصال موجود اجازه ویرایش رکورد را نمی داد و در واقع برداشت EF این بود که ما می خواهیم کلید اصلی رکورد را ویرایش کنیم. در نهایت پس از بررسی ها و جستجوی فراوان متد AsNoTracking را پیدا کردم و در متن برنامه از آن استفاده کردم. یکی از مزایای استفاده از این متد این است که می توانید رکورد واکشی شده را در LAOCAL تغییر داده و آنرا مجددا بدون محدودیت در پایگاه داده ذخیره نمایید. البته موارد مربوط به یکتایی کلید در هنگام درج رکورد شامل این قضیه نمی شود. در نهایت متد اصلی به شکل زیر تغییر کرد و مشکل حل شد. در واقع در حالتیکه ما تغییراتی روی دادههای اصلی نداشته باشیم و یا از روشهایی که به روش غیر متصل معروف هستند برای استفاده از موجودیتها استفاده می کنیم باید از متد AsNoTracking() استفاده کنیم. در این حالت رکوردهای واکشی شده از پایگاه داده در سیستم ردگیری DbContext قرار نمیگیرند و اگر وضعیت آنها را بررسی کنیم در وضعیت Detached قرار دارند.
public void CreateCustomer(int _CustomerNewCode, int PrevCode)
{
using (DbContextTransaction transaction = _context.Database.BeginTransaction())
{
try
{
Entity.CustomerServiceSupport.Customer agnt = _context.Customers.AsNoTracking().Include(m => m.CustomerBankAccounts).Include(m => m.CustomerPlaces).Include(m => m.CustomerFiles).FirstOrDefault(n => n.Code == PrevCode);
agnt.Code = _CustomerNewCode;
agnt.IsRequestCustomer = false;
foreach (var itm in agnt.CustomerFiles)
{
itm.Customer_Code = _CustomerNewCode;
}
foreach (var itm in agnt.CustomerPlaces)
{
itm.Customer_Code = _CustomerNewCode;
}
foreach (var itm in agnt.CustomerBankAccounts)
{
itm.Customer_Code = _CustomerNewCode;
}
_context.Customers.Add(agnt);
_context.SaveChanges();
Entity.CustomerServiceSupport.Customer agnt1 = _context.Customers.FirstOrDefault(n => n.Code == PrevCode);
_context.Customers.Remove(agnt1);
_context.SaveChanges();
transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
MessageBox.Show(ex.Message);
}
}
}