0

我正在使用 Simple Odata Client 在 WPF 应用程序中执行 CRUD 操作。

我有一个父实体和一个子实体:

public class Order
{
    public int OrderId{get;set;}
    public int Description{get;set;}
    public ObservableCollection<OrderLine> OrderLines {get;set;}
}
public class OrderLine
{
    public int OrderId{get;set;}
    public int OrderLineId{get;set;}
    public int ItenId{get;set;}
    public int ItemDescription{get;set;}
    public virtual Order Order {get;set;}
}

我有一个执行 crud 操作的类:

public class ManageOrders
{
    //Implements INotifyPropertyChanged
    Public Order Order;

    public void Get()
    {
        this.Order = packages = await client
                    .For<Order>()
                    .ByKey(1001).
                    .Expand(x.OrderLines).
                    .FindEntriesAsync();
    }

    public void Save()
    {
        if("NEW")
        {
            // Add new item and save
        }
        if("MODIFIED")
        {
            // save modified item
        }
    }

    public void Delete()
    {
        //Delete
    }   
}

在此处输入图像描述

我将父实体属性绑定到标题控件。

TextBox.Text = Order.Description;

和子实体到 DataGrid。

DataGrid.ItemSource = Order.OrderLines;

当我单击 GET 按钮时,将从 DB 中获取订单。然后我更改 Order 和 OrderLines 中的数据。然后我删除一个 OrderLine 并添加两个新的 OrderLine。

在我使用ObservarbleCollection时,更改将自动从 UI 添加到 Source。

要求

当我单击“保存”按钮时,所有更改都应提交到服务器。(批量请求是首选)。

问题

如何通过 PATCH 请求仅将更改的实体发送到服务器,而不在标题和行中发送未修改的属性?

4

1 回答 1

2

您在这里要求的是 IMO 网络服务和客户端框架的圣杯。

OData 中的补丁使接收和处理对象的更改属性成为可能且简单。

然而,由客户端来适当地构建数据包,这可以通过以下两种方式之一来完成:

  1. 在发送之前,客户端应将要发送的数据与上次检索的数据进行比较,以确定已更改的属性。

  2. 如果客户端上的数据包装在某种视图模型中,则视图模型可以跟踪(或监视)对属性所做的更改。

然后在发送时,客户端必须使用此信息来构建对象图的 Delta。

您还没有包含有关如何生成后端服务的 URI 的任何信息,所以我不想猜测,但无论机制如何,上述 2 种策略中的 1 种都需要实施。

如果您的后端是 OData v4 服务,那么您可能会发现 OData 客户端包是一个有用的起点。请参阅.NET 的 OData 客户端库和以下内容以生成客户端对象图:OData v4 客户端代码生成器。您可以将其用于任何实现 OData v4 规范的服务,而不仅仅是在您控制后端代码时。

支持多种批处理模式,因为批处理通常在 OData v4 实现中以不同方式实现。出于这个原因,我将批处理排除在讨论之外,但知道这些库本身就支持它并且工作得很好。

有关生成类的使用示例,请参阅此 SO 问题:What is the correct way to call patch from an odata client in web api 2或遵循我的单元测试之一:

    [TestMethod]
    public void TestPatch()
    {
        var client = ArcoCloud.Gateway.Client.Runtime.GetGatewayClient();
        var changeTracker = new Microsoft.OData.Client.DataServiceCollection<ArcoCloud.Gateway.Client.ArcoCloud_DataModel.Device>(client.Devices);

        // just change device 96
        var device = changeTracker.Single(d => d.Id == 96);
        device.Notes = "This is a test note to check if patch works natively";

        client.SaveChanges();
        /* Traced in Fiddler4
        PATCH: {
          "@odata.type": "#ArcoCloud_DataModel.Device",
          "Notes": "This is a test note to check if patch works natively"
        }*/
    }

请注意,让客户端仅发送修改后的属性是使用继承自 ObservableCollection 的 Microsoft.OData.Client.DataServiceCollection,但具有保持内部跟踪查询中对象更改的额外好处。请参阅DataServiceCollection 类

如果您确实使用 OData 客户端库和生成的类,您可以在没有 DataServiceCollection 的情况下轻松查询数据服务,但如果您这样做,更新将 PUT 整个对象图。您还会发现将更改保存回来的语法非常冗长且难以使用。这是设计使然,要回写您应该使用 DataServiceCollection。该框架提供了简单的查询机制,以便您可以简化应用程序中的流程,查询/浏览/过滤数据可以与数据编辑窗口可能用于加载和保存数据的代码隔离开来。

这是从 C# 代码与 OData v4 服务交互的官方 MS 方式。T4 模板的美妙之处在于您可以在需要的地方自定义模板或扩展生成的部分类,以便在重新生成类时不会覆盖您的业务逻辑

如果需要,您可以滚动自己的机制来支持这一点,只需记住这两个选项,或者在发生更改时跟踪更改,或者在保存之前使用比较来识别哪些字段已更改。

于 2017-03-24T02:17:13.230 回答