The SaveResult returned by both synchronous and asynchronous SaveChanges calls provides information which can help you handle save errors.
SaveResult.Ok returns "true" if the save was successful. If the save was canceled in a life-cycle handler, SaveResult.WasCancelled will return "true" and SaveResult.Ok will return "false".
If a save fails for any reason except 'Cancelation' an EntityManagerSaveException is raised. For synchronous SaveChanges calls the exception is thrown, while in SaveChangesAsync calls the exception is available on the EntitySaveOperation.
You should prepare your code to trap and analyze the save exception. The EntityManagerSaveException has the information you need to help diagnose and handle the problem.
Always handle save exceptions.
Here’s a code fragment showing a SaveAll method that matches our recommendation:
C# | internal void SaveAll() { try { MainEm.Manager.SaveChanges();// Save everything DisplaySaveOk(); } catch (EntityManagerSaveException saveException) { ProcessSaveFailure(saveException); } catch { throw; // re-throw unexpected exception } } |
VB | Friend Sub SaveAll() Try MainEm.Manager.SaveChanges() ' Save everything DisplaySaveOk() Catch saveException As EntityManagerSaveException ProcessSaveFailure(saveException) Catch Throw ' re-throw unexpected exception End Try End Sub |
The serious failure interpretation and recovery work is in the ProcessSaveFailure method, which we leave to you. Your application should determine how to process save errors, and recover from then when possible.
The EntityManagerSaveException is raised for all save-related exceptions.
If you've added a handler to the EntityManager's EntityServerError event, that handler will be called first when a save-related exception occurs. If there is no handler or it doesn’t handle the exception, the EntityManager throws it again, now in the context of the SaveChanges call.
We recommend that you do not handle save exceptions in an EntityServerError handler; leave that to the code near your SaveChanges call that traps and interprets save failures.
The EntityManagerSaveException inherits from EntityServerException, supplementing it with information about which entity/entities in the local cache caused the problem.
There are several properties on the EntityManagerSaveException that can be very useful in diagnosing the problem that occurred.
Property | Property type | Description | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
EntitiesWithErrors | IList<Object> | A list of the entities with errors. In practice, this will usually be a list of one -- the first entity to fail --. The idea here is that a non-transactional save might have multiple errors because one error would not stop the process, or multiple entities may have failed validation. Since DevForce only offers transactional saves to the datastore, the first entity to fail within a transaction causes the transaction to rollback, so no other entities are saved. | ||||||||||||
InnerException | Exception | The precipitating exception, whether from an attempt to connect to the data source or an exception from the data source itself such as a concurrency conflict or referential integrity violation. | ||||||||||||
FailureType | FailureType | A classification of the error that cause the problem. Several FailureTypes are possible.
|
These entities remain in the cache and retain exactly the values and setting they had before the save attempt. This means that you may be able to correct the entities and attempt to re-save them.