Saving is the process of sending a collection of added, modified or deleted objects to some backend datastore and having them be persisted there. The basics of performing a save are described on this page. A description of the ways in which a save operation can be intercepted or mediated will be discussed in subsequent pages.
To persist the EntityManager's cache of new, modified and deleted entities to the backend datastore, one of the following EntityManager save methods is called.
Synchronous methods:
Asynchronous methods:
A few things to note:
You use SaveOptions to specify settings controlling how the save is processed.
You'll notice in the signatures above that the SaveOptions are always optional. If not specified on a save call, the EntityManager's DefaultSaveOptions will be used. If you haven't set the DefaultSaveOptions, the defaults specified below are used.
The SaveOptions class has several interesting properties:
Property | Description | Default |
---|---|---|
TransactionSettings | Gets or sets the transactional behavior for the save. This property is described in more detail in the Manage the save transaction topic. | TransactionSettings.Default |
Tag | Used to pass custom unstructured information to the EntityServer regarding the save operation. This property can be very useful in controlling the behavior of an EntityServerSaveInterceptor. The value of the SaveOptions property, including this tag, is passed to each instance of the EntityServerSaveInterceptor during its construction. The value of this property must be serializable by the DataContractSerializer. | Null |
EntityTypesExcludedFromPostSaveRefetch | Gets or sets the types of entities which should not be returned to the client after a save. By default, all saved entities are returned to the client when the save completes. In some situations these updates are not required by the client or cause an unnecessary performance hit to send them. For example, audit entities created on the server are often not wanted on the client; or entities holding BLOBs or other large columns may not need to be refreshed on the client after the save. In these situations, the entity type can be added to this list. | Empty |
EntityTypesRequiringPostSaveRefresh | Gets or sets the types of entities to be included in the refresh that is performed after a save. By default, entities are not "refreshed" on the server before returning them to the client. This refresh involves requerying the database and can cause reduced performance. If entities of certain types must be refreshed/requeried, then add them to this list. | Empty |
IgnoreClientValidationErrors | Gets or sets a flag whether to ignore client validation errors on save. When false, the save operation that contains entities with client validation errors will not proceed to the server. When true, client validation errors are ignored and the save operation will proceed to the server. | True |
PocoSaveMode | Determines how to discover any custom server side POCO save methods. | PocoSaveMode.Default |
CommunicationRetryPolicy | Gets or sets the retry policy to use for possibly transient communication errors to a remote EntityServer. If not set the CommunicationSettings.Default.DefaultRetryPolicyForSave is used. | Null |
and one useful method:
Method Signature | Description |
---|---|
public SaveOptions WithTag(Object tag) | Used to create a clone of this SaveOptions but with the "Tag" set to the specified value. |
You may have noticed that the SaveChanges and SaveChangeAsync methods do not return any value. If the save is successful the entity cache will reflect that: all added and modified entities will now be in an unchanged state, and all deleted entities will have been removed from the cache. If real Ids were assigned during the save, these too will now be in the entity cache. If an error occurs an exception will be thrown.
If you'd like more information about the processing results of the save, or obtain the exception without using a try/catch, you can use TrySaveChanges or TrySaveChangesAsync. These methods return a SaveResult which indicates the result of the save.
The SaveResult contains the following properties:
Property | PropertyType | Description | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Ok | bool | Returns whether or not the save succeeded. This will be true, unless the Save was either canceled or an error occurred. | ||||||||||||||
SaveStatus | SaveStatus | Returns the kind of operation performed during this save.
| ||||||||||||||
SavedEntities | IList<Object> | List of entities that were saved. | ||||||||||||||
WasCancelled | bool | Returns true if the save was canceled. | ||||||||||||||
WasExceptionHandled | bool | Returns true if an exception was thrown but handled by an EntityServerError handler; otherwise false. | ||||||||||||||
Error | EntityManagerSaveException | Returns the exception (handled or unhandled) if an error occurred. | ||||||||||||||
TemporaryIdMap | UniqueIdMap | Gets copy of the UniqueIdMap that was (or would have been) used for fixup. |
SaveResult.Ok returns "true" if the save was entirely successful. ( A SaveStatus of NoOperation is still considered 'Ok').
If the save was canceled in a life-cycle handler, SaveResult.WasCancelled will return “true” and SaveResult.Ok will return "false".
If the save threw an exception and was handled, SaveResult.WasErrorHandled will return "true" and SaveResult.Ok will return "false".
On the server after entities are saved, properties backed by identity, timestamp and computed columns will have been "refreshed" as part of the save, but entire entities will not by default be refreshed from the database.
If an entity property can be set or updated via a default value, database computation or trigger, you should mark it with the appropriate StoreGeneratedPattern or Code First annotation in your model to ensure this automatic refresh occurs.
Alternately, you can force entities to be requeried and completely refreshed immediately following a save by adding the selected entity types to the SaveOptions.EntityTypesRequiringPostSaveRefresh list.
All saved entities are returned to the client's EntityManager. The revised entity is merged back into the cache, replacing the original and its EntityState becomes Unchanged. If you do not want certain entities returned to the client, for example, audit entities created on the server or entities holding BLOBs or other large columns, you can add these entity types to the SaveOptions.EntityTypesExcludedFromPostSaveRefetch list.