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

Blazor WASM中SyncFusion DataManager无法识别实体实例变更

问题描述

我开发了一个包含Invoice实体的应用,该实体包含InvoiceLine实体的集合导航属性。使用SyncFusion的DataGrid结合自定义DataManager执行CRUD操作时,点击DataGrid中的发票会显示详情组件,修改发票行后UI和本地Invoice对象的集合都能体现变更,但点击保存时,变更无法同步到服务器端的控制器。


相关代码

发票实体类(导航属性部分)

// 导航属性
public List<InvoiceLine>? InvoiceLines
{
    get => GetPropertyValue<List<InvoiceLine>?>();
    set => SetPropertyValue(value);
}

自定义DataManager类

namespace AccountsReceivable.Client.DataAdaptor
{
    public class InvoicesDataManager : SfDataManager
    {
        private IServerApiService _serverApiService = default!;

        [Inject]
        private IServerApiService ServerApiService
        {
            get => _serverApiService;
            set
            {
                if (_serverApiService != value)
                {
                    _serverApiService = value;
                    OnServerApiServiceChanged();
                }
            }
        }

        public InvoicesDataManager()
        {
            Adaptor = Syncfusion.Blazor.Adaptors.ODataV4Adaptor;
            this.EnableCaching = true;
        }
        // 设置数据管理器URL值
        private void OnServerApiServiceChanged()
        {
            // 主URL
            const string apiUrl = "api/Invoices";
            // 实例化HTTP对象
            HttpClientInstance = ServerApiService.HttpClientInstance;
            // 设置基础URL
            Url = ServerApiService.GetApiUrl(apiUrl);
            // 设置保存URL
            UpdateUrl = ServerApiService.GetApiUrl($"{apiUrl}/save");
            // 设置删除URL
            RemoveUrl = ServerApiService.GetApiUrl($"{apiUrl}/delete");
        }

        protected override void OnInitialized()
        {
            OnServerApiServiceChanged();
            base.OnInitialized();
        }
    }
}

服务器控制器代码

// PATCH: api/invoices/save
[HttpPatch("save({invoiceId})")]
[AuthorizeScope(AuthorizationScope.UpdateInvoice)]
public async Task<ActionResult> Patch([FromRoute] int invoiceId, [FromBody] IDictionary<string, JsonDocument>? values, CancellationToken ct)
{
    try
    {
        Invoice? invoice = await _invoiceDataProvider.GetItemAsync(invoiceId);
        if (invoice != null)
        {
            values?.Patch(invoice);

            await _invoiceDataProvider.SaveAsync(invoice);
        }

        return Ok(ApiResponse.OkResponse(invoice));
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "Invoice Error");
        return BadRequest(new ApiResponse(ApiStatusCodes.UnhandledError, ex.Message));
    }
}

问题原因

  1. ODataV4Adaptor默认不会自动检测集合类型导航属性的变更(比如InvoiceLines的增删改),OData的PATCH协议对复杂集合的变更处理需要明确的序列化规则,默认Adaptor未覆盖此场景。
  2. 当前使用List<InvoiceLine>作为集合类型,无法触发集合内部项变更的属性通知,导致DataManager无法感知到集合内容的变化。
  3. 控制器中使用IDictionary<string, JsonDocument>接收数据时,默认的Patch方法无法正确解析并应用集合类型的变更。

解决方案

1. 替换集合类型为ObservableCollection

将List<InvoiceLine>改为ObservableCollection<InvoiceLine>,确保集合内部项的增删改能触发属性变更通知,让DataManager感知到变更:

// 修改导航属性类型
public ObservableCollection<InvoiceLine>? InvoiceLines
{
    get => GetPropertyValue<ObservableCollection<InvoiceLine>?>();
    set => SetPropertyValue(value);
}

2. 自定义Adaptor处理集合序列化

继承ODataV4Adaptor并重写UpdateAsync方法,确保集合变更被正确序列化发送到服务器:

public class CustomInvoiceAdaptor : ODataV4Adaptor
{
    public override async Task<object> UpdateAsync(DataManagerRequest dataManagerRequest, string key, object data, string? updateUrl = null, CancellationToken cancellationToken = default)
    {
        var invoice = data as Invoice;
        if (invoice != null && invoice.InvoiceLines != null)
        {
            // 构造包含集合变更的更新数据
            var updateData = new Dictionary<string, object>
            {
                { "InvoiceLines", invoice.InvoiceLines }
                // 按需添加其他需要更新的属性
            };
            return await base.UpdateAsync(dataManagerRequest, key, updateData, updateUrl, cancellationToken);
        }
        return await base.UpdateAsync(dataManagerRequest, key, data, updateUrl, cancellationToken);
    }
}

然后在自定义DataManager中替换Adaptor:

public InvoicesDataManager()
{
    Adaptor = new CustomInvoiceAdaptor(); // 使用自定义Adaptor
    this.EnableCaching = true;
}

3. 调整控制器的变更应用逻辑

修改控制器方法,手动解析并应用集合变更:

[HttpPatch("save({invoiceId})")]
[AuthorizeScope(AuthorizationScope.UpdateInvoice)]
public async Task<ActionResult> Patch([FromRoute] int invoiceId, [FromBody] IDictionary<string, JsonDocument>? values, CancellationToken ct)
{
    try
    {
        var invoice = await _invoiceDataProvider.GetItemAsync(invoiceId);
        if (invoice != null)
        {
            // 先应用基础属性变更
            values?.Patch(invoice);
            
            // 手动处理InvoiceLines的变更
            if (values?.ContainsKey("InvoiceLines") == true)
            {
                var updatedLines = values["InvoiceLines"].Deserialize<List<InvoiceLine>>();
                if (updatedLines != null)
                {
                    invoice.InvoiceLines?.Clear();
                    invoice.InvoiceLines?.AddRange(updatedLines);
                }
            }

            await _invoiceDataProvider.SaveAsync(invoice);
        }

        return Ok(ApiResponse.OkResponse(invoice));
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "Invoice Error");
        return BadRequest(new ApiResponse(ApiStatusCodes.UnhandledError, ex.Message));
    }
}

4. 临时禁用缓存排查问题

若上述方案无效,可临时禁用DataManager缓存,确认是否是缓存导致变更未发送:

public InvoicesDataManager()
{
    Adaptor = new CustomInvoiceAdaptor();
    this.EnableCaching = false; // 临时禁用缓存
}

内容的提问来源于stack exchange,提问作者Clay Hess

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 20:27:08