Update در EntityFramework

روال بروزرسانی موجودیت‌ها در EF در 2 سناریو پیش می‌رود:
1- Connected
2- Disconnected 

1- Connected
هر موقع کوئری از دیتابیس درخواست می‌کنیم DbContext موجودیت درخواستی را از دیتابیس گرفته و آن را با وضعیت Unchanged نشان می‌کند. پس از این موجودیت رو جهت هر گونه تغییری دنبال می‌کند که به این فرآیند ChangeTracking می‌گوییم. هر موقع بر روی موجودیت تغییر اعمال کنیم Context وضعیت آن را به Modified تغییر می‌دهد. حال اگر SaveChanges را صدا بزنیم دستورات SQL بسته به وضعیت موجودیت ما تولید می‌شود. این سناریو تا زمانی که موجودیت ما با Context که آن را فراخوانی کرده متصل باشد (یعنی Context بسته یا Dispose نشده است) کار می‌کند.

private void UpdateConnected()
{
 
    Department dep;
 
    //Connected Scenario
    using (EFContext db = new EFContext())
    {
        db.Database.Log = Console.WriteLine;
 
        dep = db.Departments.Where(d => d.Name == "Accounts").First();
        dep.Descr = "This is Accounts Department";
        db.SaveChanges();
 
        Console.WriteLine("Department {0} ({1}) is Modified ", dep.Name, dep.DepartmentID);
        Console.ReadKey();
    }
 
}

در این حالت اگر به SQL تولید شده نگاه بیاندازیم می‌بینیم که فقط فیلدی که تغییرات را اعمال کردیم در دستورات مقدار داده می‌شود.

2- Disconnected
به عنوان مثال در یک وب‌اپلیکیشن کاربر مشخصات دپارتمان آی‌تی را درخواست می‌کند، ما یک نمونه جدید از Context ایجاد کرده، اطلاعات را گرفته و در نهایت آن را می‌بندیم و اطلاعات را به کاربر ارسال می‌کنیم. زمانی که کاربر اطلاعات موجودیت را بروزرسانی می‌کند ما مجدد نمونه جدیدی از Context را می‌سازیم، در این حالت Context ما از موجودیت قبلی و وضعیت آن اطلاعی ندارد پس اگر ما SaveChanges را صدا بزنیم تغییرات بر روی دیتابیس اعمال نخواهد شد. برای بروزرسانی موجودیت در این حالت باید آنرا به Context متصل کرده و وضعیت آن را به Modified تنظیم کنیم. حالا اگر متد SaveChanges را صدا بزنیم همه چیز به درستی انجام خواهد شد. مثال:

private void UpdateDisconnected()
{
    Department dep;
 
    //Disconnected Scenario
    using (EFContext db = new EFContext())
    {
        Console.Clear();
        db.Database.Log = Console.WriteLine;
        dep = db.Departments.Where(d => d.Name == "Purchase").First();
    }
 
    dep.Descr = "Purchase Department-Disconnected Scenario";
    using (EFContext db = new EFContext())
    {
 
        db.Database.Log = Console.WriteLine;
 
        db.Entry(dep).State = System.Data.Entity.EntityState.Modified;
 
        //OR
        //db.Departments.Attach(dep);
        //db.Entry(dep).State = System.Data.Entity.EntityState.Modified;
 
        //OR
        //db.Departments.Add(dep);
        //db.Entry(dep).State = System.Data.Entity.EntityState.Modified;
 
        db.SaveChanges();
    }
 
    Console.WriteLine("Department {0} ({1}) is Updated ", dep.Name, dep.DepartmentID);
    Console.ReadKey();
 
}

روش غلط ویرایش:

private void updateDepartment()
{
    updateDepartment1(2, "Purchase Department");
}
 
private void updateDepartment1(int id, string descr)
{
    Department dep = new Department();
    dep.DepartmentID = id;
    dep.Descr = descr;
 
    using (EFContext db = new EFContext())
    {
        db.Database.Log = Console.WriteLine;
 
        db.Entry(dep).State = System.Data.Entity.EntityState.Modified;
        db.SaveChanges();
      
        //NULL Value is inserted into the name field.
    }
 
    Console.WriteLine("Department {0} ({1}) is Updated ", dep.Name, dep.DepartmentID);
    Console.ReadKey();
 
}

روش صحیح ویرایش:

private void updateDepartment2(int id, string descr)
{
 
    using (EFContext db = new EFContext())
    {
        db.Database.Log = Console.WriteLine;
 
        Department dep = db.Departments.Where(f => f.DepartmentID == id).FirstOrDefault();
        if (dep == null) throw new Exception("");
 
        dep.Descr = descr;
 
        db.SaveChanges();
    }
 
    Console.WriteLine("Department {0} ({1}) is Updated ", dep.Name, dep.DepartmentID);
    Console.ReadKey();
 
}