CRM 2011 SDK транзакция
Как создать транзакцию, используя crm 2011 sdk и XrmServiceContext?
В следующем примере "new_brand" - это некоторая пользовательская сущность. Я хочу создать три бренда. Третье имеет неправильный идентификатор OwnerID Когда я вызываю метод SaveChanges(), создаются два бренда, и у меня есть исключение. Как откатить создание первых двух брендов?
Возможно ли это без использования плагинов и рабочих процессов?
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();
}
3 ответа
Возможно ли это без использования плагинов и рабочих процессов?
Нет, я не верю, что это так. каждый context.AddObject()
атомно. Если вы не хотите использовать плагины, то все, что я думаю, вы можете сделать, это иметь какую-то логику очистки, которая удаляет созданные записи, если ваши условия не выполняются.
На самом деле это возможно без использования плагинов.
Вы можете использовать ссылки отношений CRM для принудительного поведения транзакций:
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();
У этого подхода есть несколько недостатков:
- Очевидно, что в CRM должны существовать отношения между двумя сущностями. Если нет никаких отношений, вам придется пойти с плагином.
- Лично я считаю, что код может стать грязным, если вам нужно сохранить большую иерархию объектов за один раз.
Альтернативный подход может заключаться в рассмотрении реализации шаблона команды с использованием плагинов.
Идея состоит в том, что вы создаете объекты CRM на клиенте, сериализуете их и передаете их в CRM через пользовательский объект. Предварительно созданный плагин затем настраивается на эту сущность для сериализации и создания объектов в рамках транзакции плагина.
Отличный пост в блоге, описывающий обе стратегии, можно найти здесь: http://crm.davidyack.com/journal/2012/6/26/crm-client-extension-data-access-strategies.html
Единственная поддержка, которую CRM обеспечивает для транзакций, находится внутри плагина, и я даже не верю, что это поможет вам в этом случае, поскольку каждое создание бренда будет происходить в отдельной транзакции.
Самый простой способ реализовать такую логику - добавить новое поле к new_Brand с именем new_TransactionGroupId и использовать его для удаления любых записей, которые были созданы следующим образом:
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);
}
}
}