0

嗨,我是动态和动态插件的新手。我创建了一个名为 Library 的简单实体,用于存放书籍。创建新书后,我希望通过插件在服务器端将书的价格增加 10% 的 GST。

我知道这通常会在保存之前发生在页面上,因为我试图弄清楚服务器端逻辑是如何工作的。

我为“创建”消息创建了一个 postOperation(同步)步骤来调用 Plugin Execute() 方法。从我的阅读来看,这应该发生在记录保存在数据库中之后。我还有一个可以访问的帖子图像实体。

在 Execute 方法中,我尝试通过 PostMessageEntity 访问保存的记录以更新价格,但我收到一个异常,指出基于我获得的记录标识符该记录不存在。我可以确认该记录从未在系统中创建,但已调用 postOperation。

如何访问插件中刚刚保存的记录,以便更新价格?

我的代码:

public void Execute(IServiceProvider serviceProvider)
{
    // Obtain the execution context from the service provider.
    Microsoft.Xrm.Sdk.IPluginExecutionContext context = (Microsoft.Xrm.Sdk.IPluginExecutionContext)
    serviceProvider.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext));
    // create a trace log so you can see where in the code it breaks
    ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
    // create access to service
    IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
    IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
    tracingService.Trace("have reached execute event in plugin.");
    // The InputParameters collection contains all the data passed in the message request.
    if (context.InputParameters.Contains("Target") &&
    context.InputParameters["Target"] is Entity)
    {
        tracingService.Trace("We have a target and it is an entity.");
        // Obtain the target entity from the input parameters.
        Entity entity = (Entity)context.InputParameters["Target"];

        if (entity.LogicalName == "new_books")
        {
            tracingService.Trace("the entity id of the record that was created is .." + entity.Attributes["new_booksid"].ToString());
            // do we have a post update image of the new_books entity
            if (context.PostEntityImages.Contains("newbookpostImage") && context.PostEntityImages["newbookpostImage"] is Entity)
            {
                tracingService.Trace("we have a postEntityImage.");
                //    // yep lets grab it.
                Entity postMessageEntity = (Entity)context.PostEntityImages["newbookpostImage"];
                // get book price as just saved to db
                decimal bookPrice = ((Money)postMessageEntity.Attributes["new_price"]).Value;
                // get id of the the record we have
                Guid RecordID = ((Guid)postMessageEntity.Attributes["new_booksid"]);
                tracingService.Trace("we have a post update bookprice.");
                tracingService.Trace("the entity id of the post image entity is ..." + postMessageEntity.Attributes["new_booksid"].ToString());

                Entity created_book = new Entity("new_books");

                // use service to access a field of the current record as it is in the database and column we want to update.
                created_book = service.Retrieve(created_book.LogicalName, RecordID, new ColumnSet(true));

                //And the last line is where it dies and tells me new_books with id with d7bfc9e2 - 2257 - ec11 - 8f8f - 00224814e6e0 does not exist.
            }
        }
    }
}
4

2 回答 2

0

在插件管道中,您实际上可以动态添加、修改甚至删除实体对象中属性。这必须在主要操作发生之前完成:在预验证或预操作阶段。

因此,您的代码可以像这样简化:

public void Execute(IServiceProvider serviceProvider)
{
    var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
    Debug.Assert(context.Stage <= 20); // This only works in prevalidation and preoperation stages.
    var book = (Entity)context.InputParameters["Target"]; // For message Create a Target parameter is always available.

    // Using GetAttributeValue is more safe, because when price is not set, the attribute will not be available in the collection.
    decimal? price = book.GetAttributeValue<Money>("new_price")?.Value;

    if (price.HasValue)
        book["new_price"] = new Money(price.Value * 1.1M);
}

在同步后创建阶段,您仍处于数据库事务中。此时记录已创建,但尚未提交。

创建的记录的 ID 可以在OutputParameters集合中找到。你可以像这样拿起它:

var recordId = (Guid)context.OutputParameters["id"];

无需对上下文对象进行检查。当您的插件正确注册后,您希望可用的所有项目都将在那里。如果没有,适当的异常日志将是您最好的朋友。只需添加一个通用异常处理程序,负责将错误上下文写入插件跟踪日志。

于 2021-12-08T13:29:08.813 回答
0
Entity postMessageEntity = (Entity)context.PostEntityImages["newbookpostImage"];

你的 PostEntityImage 是new_books实体吗?

此外,如果您有一个实体 postMessageEntity ,您可以通过以下方式直接获取实体记录 ID

postMessageEntity.ID

而不是 Guid RecordID = ((Guid)postMessageEntity.Attributes["new_booksid"]);

在这里,您的代码只不过是创建实体 new_books 类型的空对象。您尚未设置实体或任何其他的 Priamry 名称字段。您还没有创建记录,您应该使用

Entity created_book = new Entity("new_books")

service.Create(created_book);


            Below you are trying to fecth Record from Entity new_books based on postMessageEntity.Id

您应该检查 postMessageEntity 逻辑名称是否与 created_book.LogicalName 相同,然后使用 postMessageEntity.ID 而不是 RecordID

created_book = service.Retrieve(created_book.LogicalName, RecordID, new ColumnSet(true));
于 2021-12-07T10:51:57.027 回答