what's the best practice to attach a entity object which is detached from anthoer ObjectContext?

411 views Asked by At

As mentioned in the title, how many methods are available?

I just have this case: I get a entity object from one ObjectContext, and then I detach the entity obejct from OjbectContext object, and return it.

Later, if I make some changes on this object, and I want to save the changes back to database. I think I should write like this, right? (Well, this works for me.)

public Url GetOneUrl()
{
    Url u;
    using(ServicesEntities ctx = new ServicesEntities())
    {
        u = (from t in ctx.Urls select t).FirstOrDefault<Url>();
        ctx.Detach(u);
    }
    return u;
}

public void SaveToDB(Url url)
{
   using(ServicesEntities ctx = new ServicesEntities())
   {
       var t = ctx.GetObjectByKey(_Url.EntityKey) as Url;
       ctx.Detach(t);
       ctx.Attach(url);
       ctx.ObjectStateManager.ChangeObjectState(url, System.Data.EntityState.Modified);
       ctx.SaveChanges();
   }
}

Url url = GetOneUrl();
url.UrsString = "http://google.com"; //I just change the content.
SaveToDB(url);

OR

public void SaveToDB(Url url)
{
    using(ServicesEntities ctx = new ServicesEntities())
    {
        var t = ctx.GetObjectByKey(_Url.EntityKey) as Url;
        t = url; //this will make t.UrlString becomes "http://google.com"
        ctx.ApplyCurrentValues<Url>("Urls", t);
        ctx.SaveChanges();
    }
}

This way is also works for me.

The first way will generate sql statement to update all the columns of Url table, but the second method will provide a sql script only update the "UrlString" Columns.

Both of them will have to retrieve a temp entity object from database which is the 't' in above code.

Are there any other methods to achieve this purpose? Or other better method you know about it? Or any official solution about this topic?

Many Thanks.

1

There are 1 answers

1
Ladislav Mrnka On

I don't understand your first example. Why do you first get entity from ObjectContext? It is not needed because you have just created new instance of the context. You can just use:

public void SaveToDB(Url url)
{
   using(ServicesEntities ctx = new ServicesEntities())
   {
       ctx.Attach(url);
       ctx.ObjectStateManager.ChangeObjectState(url, System.Data.EntityState.Modified);
       ctx.SaveChanges();
   }
}

In your second example you can just call:

public void SaveToDB(Url url) 
{     
  using(ServicesEntities ctx = new ServicesEntities())     
  {         
     var t = ctx.GetObjectByKey(_Url.EntityKey) as Url; // Ensures that old values are loaded
     ctx.ApplyCurrentValues<Url>("Urls", url);         
     ctx.SaveChanges();     
  } 
} 

Now the difference between two approaches is clear. First approach (Attach) does not need to query the DB first. Second approach (ApplyCurrentValues) needs to query the DB first to get old values.

You can use two additional approaches. First is just extension of your former approach. It allows you defining which properties were changed. Second approach is manual synchronization with loaded entity. This approach doesn't use any special methods. You will simply set loaded entity's properties to required values manually. This approach is useful if you work with object graph instead of single entity because EF is not able to automatically synchronize changes in relations.