5

如何使用 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();
}
4

3 回答 3

3

实际上,这在不使用插件的情况下是可能的。

您可以使用 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

于 2013-03-07T12:50:09.830 回答
2

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);
        }
    }
}
于 2012-06-14T15:10:46.603 回答
1

是否可以不使用插件和工作流程?

不,我不相信它是。每个context.AddObject()都是原子的。如果您不想使用插件,那么我认为您所能做的就是拥有某种清理逻辑,如果您的条件不满足,则删除创建的记录。

于 2012-06-14T10:32:04.593 回答