Create, Get, and Save Entity Activities

When a form sequence is created and saved, Sequence Designer automatically creates a workflow definition containing In/Out arguments for all entities that are referenced in the forms within the sequence. The arguments are used to pass data between Forms Builder and Workflow Composer. The argument names match the entity types. The parameters associated with the entities are not initialized by default. The entities associated with the arguments are not automatically created in the workflow. It is the responsibility of the user building the form to add the necessary CreateEntity<>, GetEntity<>, and SaveEntity<> activities in appropriate locations of the workflow definition. Appropriate locations are Transitions (e.g., Next, Submit, Back) and States (i.e., forms) in the StateMachine workflow.

CreateEntity<>

The CreateEntity<> activity is usually placed in the Entry Sequence of the first State (form) in a StateMachine workflow. Often, one or more Assign activities follow the CreateEntity<> activity.

CreateEntity

GetEntity<>

The GetEntity<> activity can be used to retrieve data from the database. The activity could be placed on the Welcome form so that previously entered data prefills the form fields when the form is displayed.

GetEntity

The following table illustrates the behavior of Forms Builder and Workflow Composer depending on the user scenario. The StudentEntity and ContactEntity are used as examples in the table; however, the concept applies to other entities as well.

User scenario Which workflow activity is needed in the first form? Is the FormInstance.UserInfo property populated in Workflow Composer? Is the Login field populated on the form? Notes
Anthology Student
Anonymous user CreateEntity — StudentEntity — NA — — NA —  
New user creating an account CreateEntity — StudentEntity Yes Yes Add an Assign activity to assign studentEntity.FirstName = formInstance.UserInfo.FirstName

The FormInstance.UserInfo comes from the login account information.

The same assignment can be done for all other account fields in FormInstance.UserInfo to prepopulate those fields for StudentEntity in form.

Existing user logged in GetEntity — StudentEntity Yes Yes  
CampusNexus CRM
Anonymous user CreateEntity — ContactEntity — NA — — NA —  
New user registering as a contact GetEntity — ContactEntity No (get data from the ContactEntity) No by default (get data from the ContactEntity)  
Existing user logged in GetEntity — ContactEntity No (get data from the ContactEntity) No by default (get data from the ContactEntity)  

SaveEntity<>

The SaveEntity<> activity can be placed in the Trigger or Action area of the Next transition that leads to the End State. A SaveEntity<> activity must be paired with each CreateEntity<> or GetEntity<> activity to ensure that the data collected in the form sequence is persisted to the database.

SaveEntity

See Workflow Help for more details on the CreateEntity<>, GetEntity<>, and SaveEntity<> activities.

Best Practice to Prevent DbUpdateConcurrency Exceptions

A DbUpdateConcurrency error occurs when an attempt is made to update an instance of an entity via a Save activity, but that instance has been modified by another user in the time from when the instance was initially retrieved in the workflow to the point in time when the Save activity executes. Closed

Example of a DbUpdateConcurrency exception in a Renderer log file:

2018-02-27 13:30:16.7645 54 Error Cmc.Nexus.Crm.Workflow.SaveDocument System.ServiceModel.FaultException`1[System.ServiceModel.ExceptionDetail]: Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions. (Fault Detail is equal to An ExceptionDetail, likely created by IncludeExceptionDetailInFaults=true, whose value is: System.Data.Entity.Infrastructure.DbUpdateConcurrencyException: Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions. ----> System.Data.Entity.Core.OptimisticConcurrencyException: Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions. at System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.ValidateRowsAffected(Int64 rowsAffected, UpdateCommand source) at System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.Update() at System.D...).

The best practice to avoid this error is to add a TransactionScope activity to the workflow. Use the defaults of IsolationLevel = Serializable, and a timeout of 1 minute.

Within that TransactionScope, add a GetEntity activity to retrieve the instance of the entity prior to the execution of the SaveEntity activity. Any property values that need to be updated prior to saving can be done so via Assign statements right after the Get activity and right before the Save activity.

A transaction locks the database to give the workflow a chance to read and update with no other process simultaneously doing the same. Read about the other less aggressive isolation levels as they may be adequate for the purpose based on the type of updates being done and produce less overhead. Google “TransactionScope IsolationLevel Activities”. A “RepeatableRead” may be sufficient.

This pattern will eliminate any chance that another user will update this record in between the execution of the Get and Save activities within the workflow.