Francisco Goldenstein
Francisco Goldenstein

Reputation: 13767

Entity Framework 6 and ObjectCache: saving issues

I'm using Entity Framework 6 and ObjectCache to cache some entities that don't change often. But I faced an error when trying to save entities that are cached because they were retrieved from a different context. Before saving, I verified and the state of the object was detached but couldn't get rid of that error until I did this:

public void Save(Product obj)
{
    var objInDb = dbContext.Products.Find(obj.Id);

    if (objInDb == null)
    {
        dbContext.Products.Add(obj);
        dbContext.SaveChanges();
    }
    else
    {
        dbContext.Entry(objInDb).CurrentValues.SetValues(obj);
        dbContext.Entry(objInDb).State = EntityState.Modified;
        dbContext.SaveChanges();
    }
}

Original error that was fixed after implemented the described solution: Attaching an entity of type 'C' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.

The original code was:

if (obj.Id == 0)
{
    context.Products.Add(obj);
}
else
{
    context.Entry(obj).State = EntityState.Modified;
}

context.SaveChanges();

Is there a better way to handle this? I really don't like to bypass my cache and hit the DB to get the object because it looks unnecessary to me.

Upvotes: 6

Views: 148

Answers (1)

Henrique Campos
Henrique Campos

Reputation: 561

I think the only way of not "hitting" de db would be something like the following. Please keep in mind that, based on your first exception, you are already "hitting" the db for this entity somewhere else.

if (obj.Id == 0)
{
    context.Products.Add(obj);
}
else
{
    var localProduct = context.Products.Local.FirstOrDefault(x => x.Id == obj.Id);
    if (localProduct == null)
    {
        context.Entry(obj).State = EntityState.Modified;
    }
    else
    {
        context.Entry(localProduct).CurrentValues.SetValues(obj);
    }
}
context.SaveChanges();

Upvotes: 0

Related Questions