# 操作服务插件 — C#（AbstractOperationServicePlugIn）

**访问位（任意字段）：**

| 代码 | 层 |
|------|-----|
| `e.FieldKeys.Add(...)` | **Key** |
| `entity[...]` / 分录 `DynamicObject[...]` | **PropertyName** |
| 失败 | 抛 `KDException` / `KDBusinessException`；**无 View 主路径** |

禁止：`entity["FQty"]` 等把 Key 当数据包键；禁止口算去 F。见 `api-surface-contract.md`。

```csharp
using Kingdee.BOS;
using Kingdee.BOS.App.Data;
using Kingdee.BOS.Core;
using Kingdee.BOS.Core.DynamicForm.PlugIn;
using Kingdee.BOS.Core.DynamicForm.PlugIn.Args;
using Kingdee.BOS.Orm.DataEntity;
using Kingdee.BOS.Util;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;

namespace Kingdee.MyProject.Plugin.Operation
{
    [Description("操作服务插件说明"), HotUpdate]
    public class MyOperationPlugin : AbstractOperationServicePlugIn
    {
        /// <summary>选项设置：操作初始化时</summary>
        public override void OnPrepareOperationServiceOption(OnPrepareOperationServiceEventArgs e)
        {
            base.OnPrepareOperationServiceOption(e);
            e.SupportTransaction = true;
            e.SurportBatchTransaction = false;
        }

        /// <summary>字段预加载：声明 Key（标识）</summary>
        public override void OnPreparePropertys(PreparePropertysEventArgs e)
        {
            base.OnPreparePropertys(e);
            e.FieldKeys.Add("FQty");
            e.FieldKeys.Add("FPrice");
            e.FieldKeys.Add("FAmount");
            e.FieldKeys.Add("FBillTypeID");
        }

        /// <summary>校验器干预：添加/移除自定义校验器</summary>
        public override void OnAddValidators(AddValidatorsEventArgs e)
        {
            base.OnAddValidators(e);
        }

        /// <summary>操作事务前（事务外）：强制校验；数据包索引用 PropertyName</summary>
        public override void BeforeExecuteOperationTransaction(BeforeExecuteOperationTransaction e)
        {
            base.BeforeExecuteOperationTransaction(e);
            if (e.DataEntitys == null) return;
            foreach (var entity in e.DataEntitys)
            {
                // PropertyName（元数据）；下例为假设
                decimal amount = Convert.ToDecimal(entity["Amount"] ?? 0);
                if (amount <= 0)
                    throw new KDException("", "金额必须大于零");

                var entries = entity["SaleOrderEntry"] as IEnumerable;
                if (entries == null) continue;
                int i = 0;
                foreach (var rowObj in entries)
                {
                    var entry = rowObj as DynamicObject;
                    if (entry == null) { i++; continue; }
                    decimal qty = Convert.ToDecimal(entry["Qty"] ?? 0);
                    if (qty <= 0)
                        throw new KDException("", $"第 {i + 1} 行数量必须大于零");
                    i++;
                }
            }
        }

        /// <summary>操作事务中（事务内，支持回滚）：数据准备</summary>
        public override void BeginOperationTransaction(BeginOperationTransactionEventArgs e)
        {
            base.BeginOperationTransaction(e);
            foreach (DynamicObject billObj in e.DataEntitys)
            {
                string billId = Convert.ToString(billObj["Id"]);
                string billNo = Convert.ToString(billObj["BillNo"]); // PropertyName
            }
        }


        /// <summary>操作事务后（事务内，支持回滚）：SQL更新等</summary>
        public override void EndOperationTransaction(EndOperationTransactionEventArgs e)
        {
            base.EndOperationTransaction(e);
            foreach (DynamicObject billObj in e.DataEntitys)
            {
                string billId = Convert.ToString(billObj["Id"]);
                string sql = $"/*dialect*/ UPDATE T_MYTABLE SET FSTATUS = 'C' WHERE FID = '{billId}'";
                DBUtils.Execute(this.Context, sql);
            }
        }

        /// <summary>回滚数据（事务外）：发生异常时触发</summary>
        public override void RollbackData(RollbackDataEventArgs e)
        {
            base.RollbackData(e);
            // 回滚内存数据
        }

        /// <summary>操作事务后（事务外）：同步数据、追加提示</summary>
        public override void AfterExecuteOperationTransaction(AfterExecuteOperationTransaction e)
        {
            base.AfterExecuteOperationTransaction(e);
            foreach (DynamicObject billObj in e.DataEntitys)
            {
                // 追加自定义提示
                var result = new OperateResult
                {
                    SuccessStatus = true,
                    Message = "处理完成"
                };
                this.OperationResult.OperateResult.Add(result);
            }
        }
    }
}
```

**AbstractOperationServicePlugIn 全部事件（反编译 Kingdee.BOS.Core.dll）：**
**OnPrepareOperationServiceOption**(OnPrepareOperationServiceEventArgs) / **OnAddValidators**(AddValidatorsEventArgs) / **OnPreparePropertys**(PreparePropertysEventArgs) / BeforeDoSaveExecute(BeforeDoSaveExecuteEventArgs) / **BeforeExecuteOperationTransaction**(BeforeExecuteOperationTransaction) / **AfterExecuteOperationTransaction**(AfterExecuteOperationTransaction) / **BeginOperationTransaction**(BeginOperationTransactionArgs) / **EndOperationTransaction**(EndOperationTransactionArgs) / **RollbackData**(OperationRollbackDataArgs) / InitializeOperationResult(IOperationResult) / AfterExecuteValidate(AfterExecuteValidateArgs)

**源码参考：** `lf-project/Kingdee.LF.Plugin/Plugin/Operation/` — MesBomSyncOperationPlugin.cs
