You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Dynamics 365中如何避免OpportunityProduct与lotCommercial并发关联冲突

问题描述

我正在使用Dynamics 365,在OpportunityProduct实体的PreCreate事件上注册了一个插件。需要防止两名用户同时为同一个名为lotCommercial的自定义实体创建OpportunityProduct,避免并发创建导致重复关联。

起初尝试用versionnumber做并发控制,但因为是PreCreate插件,实体还未创建,无法获取versionnumber。
后来实现了查询现有记录、检测到冲突就抛出异常的逻辑,但两名用户完全同时创建时,两者的验证都通过,最终生成两条记录——这个检查不具备原子性,不可靠。

目标是通过插件或Dynamics 365推荐的机制,简洁可靠地阻止这类竞态条件,该如何实现这类锁定?

现有插件代码
tracer.Trace("Vérification de la création simultanée de options...");

QueryExpression query = new QueryExpression("opportunityproduct");
query.ColumnSet.AddColumns("vista_lotcommercialid", "vista_statutoption");
query.Criteria.AddCondition("vista_statutoption", ConditionOperator.Equal, 3);
query.Criteria.AddCondition("vista_lotcommercialid", ConditionOperator.Equal, option.GetAttributeValue<EntityReference>("vista_lotcommercialid").Id);
//query.Criteria.AddCondition("createdon", ConditionOperator.GreaterEqual, DateTime.UtcNow.AddMilliseconds(-500));
EntityCollection existingOptions = service.RetrieveMultiple(query);
tracer.Trace("after retrieve opportunities.");
if (existingOptions.Entities.Count > 0)
{
    tracer.Trace("Exception ");
    throw new InvalidPluginExecutionException("Une option est déjà en cours. Vous ne pouvez pas en créer une nouvelle simultanément.");
}
tracer.Trace("existingOptions: " + existingOptions.Entities.Count.ToString());
tracer.Trace("End of blocage pose precreateoption  s'il y a 2 créations simultanées : " + DateTime.Now.ToLocalTime().ToString("dd/MM/yyyy HH:mm"));
解决方案

针对Dynamics 365中这种并发创建的竞态条件,推荐以下几种可靠实现方式:

1. 数据库级排他锁(推荐)

通过Retrieve操作的LockingMode参数对关联的lotCommercial记录加排他锁,确保当前事务完成前,其他事务无法修改或创建关联的OpportunityProduct,从根源保证验证与创建的原子性。

修改插件逻辑如下:

// 获取要关联的lotCommercial实体ID
Guid lotId = option.GetAttributeValue<EntityReference>("vista_lotcommercialid").Id;

// 以排他锁方式检索lotCommercial记录,锁定该记录直至事务结束
Entity lotCommercial = service.Retrieve(
    "vista_lotcommercial", 
    lotId, 
    new ColumnSet(true), 
    new RetrieveRequest { LockingMode = LockingMode.Exclusive }
);

// 执行原有的OpportunityProduct查询验证
QueryExpression query = new QueryExpression("opportunityproduct");
query.ColumnSet.AddColumns("vista_lotcommercialid", "vista_statutoption");
query.Criteria.AddCondition("vista_statutoption", ConditionOperator.Equal, 3);
query.Criteria.AddCondition("vista_lotcommercialid", ConditionOperator.Equal, lotId);

EntityCollection existingOptions = service.RetrieveMultiple(query);
if (existingOptions.Entities.Count > 0)
{
    throw new InvalidPluginExecutionException("已存在关联的有效记录,无法重复创建。");
}

2. 自定义唯一性约束(元数据配置)

如果业务规则是每个lotCommercial只能关联一条状态为3的OpportunityProduct,可以直接在Dynamics 365平台配置唯一约束,无需编写插件:

  • 打开对应解决方案,进入OpportunityProduct实体的字段配置界面
  • 创建新的唯一约束,添加vista_lotcommercialid和vista_statutoption两个字段
  • 保存并发布解决方案

这种方式由数据库层面强制执行唯一性,是最简洁可靠的方案,仅适用于固定的唯一性规则场景。

3. PostCreate事务回滚验证

若上述两种方式无法适用,可将验证逻辑移至PostCreate事件,结合事务回滚:

  • 在PreCreate事件中暂存关联的lotCommercial ID
  • 在PostCreate事件中再次查询是否存在重复的OpportunityProduct记录
  • 若发现重复,抛出InvalidPluginExecutionException触发事务回滚,删除已创建的重复记录

注意:这种方式会有短暂的重复记录存在,可靠性略低于前两种方案。

内容的提问来源于stack exchange,提问作者Manel Ben Sayari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 23:03:15