Reputation: 15160
I have the following code (EntityContext.Current is a DbContext):
try {
Setting s = new Setting
{
id = 1,
user_id = 0
};
EntityContext.Current.Settings.Add(s);
EntityContext.Current.SaveChanges(); //this violates a foreign key constraint and therefore throws an exception
} catch (Exception ex) {
ErrorContext.Log(ex);
}
What I would expect (as per this answer) is that the pending changes would be rolled back when they have failed. However, In my error logging method, I see that they have not been.
Error e = new Error
{
message = ex.Message
};
EntityContext.Current.Errors.Add(e);
var pending = ((IObjectContextAdapter)EntityContext.Current).ObjectContext.ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Added);
//this contains both my new error entity and my old setting entity which shouldn't be here
EntityContext.Current.SaveChanges();
When my application attempts to log the error in the database, it also tries (again) to save the setting with the invalid foreign key constraint, which then causes the addition of the error log record to fail.
This is the first time I've ran into this behavior with EF. I tried wrapping the first SaveChanges()
in a transaction but the same issue occurred.
As per this answer my connection string does not contain Enlist=false
either. I'm at a loss. Is this expected behavior? And how can I prevent this from happening?
Upvotes: 3
Views: 2295
Reputation: 177153
This is expected behaviour. SaveChanges
attempts to commit all changes in a single database transaction. If it fails the database transaction is rolled back and nothing will be written to the database.
But the failed transaction won't change the state of entities in the context. That's why your Setting
entity is still in state Added
.
Attaching your Error
entity to the same context is a problem since you often won't be able to store it to the database, like in this example. I would consider to write the error log always in a new context with a dedicated method that just only opens a new context, adds the Error
entity to this context and saves the changes. Then dispose it immediately.
Upvotes: 3