Reputation: 2017
How to create transaction using crm 2011 sdk and XrmServiceContext?
In next example 'new_brand' is some custom entity. I want to create three brands. Third has wrong OwnerID guid. When I call SaveChanges() method, two brands are created and I've got exception. How to rollback creating of first two brands?
Is it possible without using pluggins and workflows?
using (var context = new XrmServiceContext(connection))
{
SystemUser owner = context.SystemUserSet.FirstOrDefault(s => s.Id == new Guid("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"));
// create 3 brands
new_brand b1 = new new_brand();
b1.new_brandidentification = 200;
b1.new_name = "BRAND 200";
b1.OwnerId = owner.ToEntityReference();
context.AddObject(b1);
new_brand b2 = new new_brand();
b2.new_brandidentification = 300;
b2.new_name = "BRAND 300";
b2.OwnerId = owner.ToEntityReference();
context.AddObject(b2);
new_brand b3 = new new_brand();
b3.new_brandidentification = 400;
b3.new_name = "BRAND 400";
b3.OwnerId = new EntityReference(SystemUser.EntityLogicalName, new Guid("00000000-0000-0000-0000-000000000000"));
context.AddObject(b3);
context.SaveChanges();
}
Upvotes: 5
Views: 4795
Reputation: 141
Actually this is possible without the use of Plugins.
You can use CRM relationship links to force transactional behaviour:
EntityA primaryEntity = new EntityA() { //initialise me... };
EntityB secondaryEntity = new EntityB() { //initialise me... };
context.AddObject(primaryEntity);
context.AddObject(secondaryEntity);
// This is the key part: explicitly link the two entities
context.AddLink(primaryEntity,
new Relationship("relationship_name_here"), secondaryEntity);
// commit changes to CRM
context.SaveChanges();
There are a few drawbacks to this approach:
An alternative approach might be to consider implementing a command pattern using plugins.
The idea is that you create the CRM objects on the client, serialize them and pass them to CRM via a custom entity. A pre-create plugin is then set-up on this entity to de serialize and create the objects within the plugin transaction scope.
An excellent blog post describing both strategies can be found here: http://crm.davidyack.com/journal/2012/6/26/crm-client-extension-data-access-strategies.html
Upvotes: 3
Reputation: 18895
The only support CRM provides for transactions is within a plugin, and I don't even believe that will help you in this case, since each creation of a brand, will take place in its own transaction.
The easiest way I can think of to implement this sort of logic is adding a new field to new_Brand called new_TransactionGroupId, and use it to delete any records that were created like so:
using (var context = new XrmServiceContext(connection))
{
SystemUser owner = context.SystemUserSet.FirstOrDefault(s => s.Id == new Guid("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"));
var transactionGroupId = Guid.NewGuid();
// create 3 brands
new_brand b1 = new new_brand();
b1.new_brandidentification = 200;
b1.new_name = "BRAND 200";
b1.OwnerId = owner.ToEntityReference();
b1.new_TransactionGroupId = transactionGroupId ;
context.AddObject(b1);
new_brand b2 = new new_brand();
b2.new_brandidentification = 300;
b2.new_name = "BRAND 300";
b2.OwnerId = owner.ToEntityReference();
b2.new_TransactionGroupId = transactionGroupId ;
context.AddObject(b2);
new_brand b3 = new new_brand();
b3.new_brandidentification = 400;
b3.new_name = "BRAND 400";
b3.OwnerId = new EntityReference(SystemUser.EntityLogicalName, new Guid("00000000-0000-0000-0000-000000000000"));
b3.new_TransactionGroupId = transactionGroupId;
context.AddObject(b3);
try{
context.SaveChanges();
} catch (Exception ex){
// Since one brand failed, cleanup all brands
foreach(brand in context.new_brand.where(b => b.new_TransactionGroupId == transactionGroupId)){
context.Delete(brand);
}
}
}
Upvotes: 2
Reputation: 3878
Is it possible without using plugins and workflows?
No I don't believe that it is. Each context.AddObject()
is atomic. If you don't want to use plug-ins then all I think you can do is have some sort of clean-up logic that deletes the created records if your conditions are not met.
Upvotes: 1