Reputation: 16121
Linq To SQL's DataContext
has an overload on SubmitChanges
that allows for updates to continue when a Optimistic Concurrency Exception is thrown, and provides the developer with a mechanism to resolve the conflicts afterwards in a single Try Catch block.
Even the WCFDataServicesContext
has a SaveChangedOptions.ContinueOnError
parameter for its SaveChanges
method that at least allows you to continue updating when an error has occurred and leaves conflicting updates unresolved so you can look into them later.
(1) Why then does the ObjectContext.SaveChanges
method have no such option?
(2) Do any update patterns exist that will mimick the Linq To SQL behaviour? The examples I find on MSDN make it appear as if a single Try Catch block will see you home in the case of multiple updates. But this pattern does not allow you to investigate each conflicting update separately: it just alerts you to the first conflict and then gives you the option to "wipe the table clean in one sweep" to prevent any further optimistic concurrency exceptions from surfacing, without your knowing if any exist and what you would have liked to do about them.
Upvotes: 2
Views: 666
Reputation: 364369
Why then does the ObjectContext.SaveChanges method have no such option?
I think the simplest answer is because Linq-to-Sql, Entity Framework and WCF Data Services were all implemented by different teams and internal communication among these teams doesn't work as we would hope. I have described some interesting features missing in newer APIs in one of my former answers but I don't think this is a missing feature - I will explain it in the second part of my answer.
WCF Data Services have more interesting features which should be part of Entity framework as well. For example:
Do any update patterns exist that will mimick the Linq To SQL behaviour?
There is a pattern how to solve this but you will probably not like it. EF's SaveChanges
works as Unit of work. It either saves all changes or none. If you have a scenario where your saving operation can result in case where only part of your changes is persisted than it should not be handled by single SaveChanges
call. Each atomic set of changes should have its own SaveChanges
call:
using (var scope = new TransactionScope(...)) {
foreach (var entity in someEntitiesToModify) {
try {
context.SomeEntities.Attach(entity);
context.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
context.SaveChanges();
catch (OptimisticConcurrencyException e) {
// Do something here
context.Refresh(e.StateEntries[0].Entity, RefreshMode.ClientWins);
context.SaveChanges();
}
}
scope.Complete();
}
I think the reason why this feature doesn't exist is because it is not generic and as mentioned about it goes against unit of work pattern. Suppose this example:
SqlException
because the principal entity doesn't exist in the database. This exception will break the persistence operation and you will not know why it is complaining about referential integrity because you have a principal entity. (It is possible that this insert will even not happen and EF fires another exception due to inconsistency of context's inner state but it depends on EF's internal implementation).This immediately makes whole relaxing of conflict resolution much more complex feature. There are IMHO three ways to solve it:
It doesn't mean it may not be possible to make such functionality but it will need to cover all scenarios when it comes to relations and this can be pretty complex. I'm not sure if Linq-to-Sql handles this.
You can always make a suggestion on Data UserVoice or check out the code and try to implement it yourselves. Maybe I see this feature too complicated and it can be implemented easily.
Upvotes: 5