EF keeps trying to persist invalid object

I'm having a rather strange issue with Entity Framework 4.3 in my MVC application. I'm using a Unit of Work wrapper around DbContext, and in my MVC application I use Unity to pass this UOW to my repositories, and repositories to controllers. I've registered the UOW type with the HierarchicalLifetimeManager.

When I try to persist an entity to the database that raises an error, e.g. the database throws a UNIQUE constraint violation, the entity is kept inside EF's ObjectStateManager. So when I go back in my application to fix the error and save the new entity (without errors), EF first tries to add the old and invalid object again, thus failing with the same error.

What am I missing here? I believe that the invalid object should be completely forgotten by EF and that this would be done automatically. But it's clearly not the case.

To add objects to DbContext in order to persis them, the following command gets called (where base is the DbContext):

base.Set<TEntity>().Add(objectToPersist);

And to commit the changes to the database, I call:

base.SaveChanges();

Which throws the error.

Answers


I believe that the invalid object should be completely forgotten by EF and that this would be done automatically. But it's clearly not the case.

Right, that's not the case and I've never heard that entities would be detached from the context automatically when an exception occured.

There are basically two options to deal with the problem. I show a simple model with your example of a unique key constraint violation:

public class Customer
{
    // so we need to supply unique keys manually
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int Id { get; set; }
    public string Name { get; set; }
}

public class MyContext : DbContext
{
    public DbSet<Customer> Customers { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        Database.SetInitializer(new DropCreateDatabaseAlways<MyContext>());

        using (var ctx = new MyContext())
        {
            var customer = new Customer { Id = 1, Name = "X" };
            ctx.Customers.Add(customer);
            ctx.SaveChanges();
        }
        // Now customer 1 is in database

        using (var ctx = new MyContext())
        {
            var customer = new Customer { Id = 1, Name = "Y" };
            ctx.Customers.Add(customer);

            try
            {
                ctx.SaveChanges();
                // will throw an exception because customer 1 is already in DB
            }
            catch (DbUpdateException e)
            {
                // customer is still attached to context and we only
                // need to correct the key of this object
                customer.Id = 2;
                ctx.SaveChanges();
                // no exception
            }
        }
    }
}

The above is the prefered solution: Correct the object which is attached to the context.

If you need - for whatever reason - to create a new object you must detach the old object from the context. That object is still in state Added and EF will try to save the object again when you call SaveChanges leading to the same exception as before.

Detaching the old object would look like this:

            try
            {
                ctx.SaveChanges();
                // will throw an exception because customer 1 is already in DB
            }
            catch (DbUpdateException e)
            {
                ctx.Entry(customer).State = EntityState.Detached;
                // customer is now detached from context and
                // won't be saved anymore with the next SaveChanges

                // create new object adn attach this to the context
                var customer2 = new Customer { Id = 2, Name = "Y" };
                ctx.Customers.Add(customer2);
                ctx.SaveChanges();
                // no exception
            }

This procedure can be tricky if relationships are involved. For example if customer has a relationship to a list of orders, detaching the customer object will delete references between customer and its orders if the orders are attached to the context as well. You have to reestablish the relationships with the new customer2.

Therefore I'd prefer to modify the attached object to put it into correct state. Or let the application crash because such constraint violations usually indicate bugs in the code or - in a multiuser environment - should be handled with proper optimistic concurrency checks.


looks like you'll have to tell EF that you changed your mind about the invalid object:

base.Set().Remove(objectToPersist);


If you want to reset the changes, you could set the ObjectContext to null and re-instantiate it.


Need Your Help

javascript function errors when trying to return a value

javascript jquery function

My Goal: I am writing a widget for a job which will populate a div with contents. I dont even get to execute the information as get the error: