开发者

Entity Framework single method for Save/Update

The problem is I'm trying to find a single method to save an entity, be it a new entity or an already loaded entity. Most all code samples separate Add and Save methods which goes against so many other current designs of having a single Save() method.

Let me state I've read the other posts. I've looked at the team blog on repository pattern as well which has a single AddObject() method that I can't seem to find by assuming it just is an Add(object).

If we load an object and save it, the context knows about it. A new object we MUST add. If we add an existing object - it will send it over as an insert.

I want one save procedure here. A user shouldn't have to know to call Add or Update, a Save() should suffice. With that said, whats the best route here for a single save solution that covers in the same method (only the save, not the load): 1. loading an entity, saving back to the db. 2. Creating a new entity, saving it to the db. So I'm looking for an implementation that in all cases can just be

ICustomerRepository.Save(Customer customer)

What solution would you be using that works?

The following code in a Save(entity) method seems to work for me


//If the primary key is empty, its a new record
if (order.OrderId == 0)
{
   _context.Orders.Add(order);
}

if (_context.Entry(order).State == System.Data.EntityState.Detached)
{
   //Need to set modified so any detached entities are updated otherwise they won't be sent across to the db. Since it would've been outside the context, change tracking wouldn't have occurred anyways so we have no idea about its state - save it!
   _context.Orders.Attach(order);
   _context.Entry(order).State =开发者_高级运维 System.Data.EntityState.Modified;
}


The issue here though is with a Generic Repository implementation there is no clear way here without querying what the key is and checking its value then via reflection which isn't clean.


Generic repository is fairy tale. The only valid usage of repository pattern is specific repository and specific repository knows what type the key is and what is its default value. In the same way you can complain that your generic code will not work if your keys are not generated in the database but in the application.

EF doesn't have any support for single method processing and it cannot be simply added. To make it work correctly you would need something on SQL level to do conditional insert / update (or merge in SQL server 2008). EF doesn't have anything like that and it separates both operations all the way to command execution.

That means the only way to achieve that is either using some "knowledge" as you shown in your code sample or by checking existence of the entity in database with separate database call or using stored procedure.


public abstract class EntityObject
{
    /*Allows for this:
        T UpdateOrInsert<T>(T item) where T : EntityObject
        {
            T foundItem = depDA.Set<T>().Find(item.EntityKey);
            return foundItem;
        }
    etc


     inherit entity partials from this

     partial class MyObject : EntityObject
     {
         override int EntityKey { get { return MyObjectID; } } 
     }

    */

    public abstract int EntityKey { get; }

}

pop this method into a Helper class

public static T SaveEntity<T>(T item, DbContext context) where T : EntityObject
{
    T foundItem = context.Set<T>().Find(item.EntityKey);
    if (foundItem == null)
    {
        //INSERT
        foundItem = context.Set<T>().Add(item as T);
    }
    else
    {
        //UPDATE
        foundItem = item;
    }
    context.SaveChanges();
    return foundItem;
}

Voila!


If you use self tracking entities then the entity will keep track of the state and Insert or Update as needed without having to have separate methods

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜