8

通过阅读Patch 动词的 RFC 规范,很明显Patch动词不应该获取值来部分更新实体,而是要进行操作:

...但是,对于 PATCH,封闭的实体包含一组指令,描述如何修改当前驻留在源服务器上的资源以生成新版本。

在 Delta 类的 MSDN 中,它也很清楚,正如补丁描述所说:

使用此 Delta跟踪的更改覆盖原始实体。

Put的描述不同:

使用存储在此 Delta 中的覆盖原始实体。

到目前为止一切顺利,但我找不到用 OData 发送这些“指令”的方法,无论我做什么,Delta.Patch 只会替换这些值。

补丁请求的语法应该是什么?

我尝试的方法是:

PATCH http://localhost:55783/Products(1) HTTP/1.1
User-Agent: Fiddler
Host: localhost:55783
Content-Length: 19
Content-type: application/json

{ "Price": 432 }

{ "op": "add", "path": "/Price", "value": 423432 }

和附近的东西。


更新:

感谢 Michael Moore 并阅读了 ILSpy 的整个 Delta 课程,我认为这确实是 Patch 动词设计中的一个错误。
我为微软打开了一个错误,如果你也需要修复它,你可以投票。

4

1 回答 1

13

我不确定您要实现的目标是否可行。至少不与Delta<TEntity>.Patch(..)

假设你有Product实体并且在你的PATCH行动中你有

[AcceptVerbs("PATCH")]
public void Patch(int productId, Delta<Product> product)
{
    var productFromDb = // get product from db by productId
    product.Patch(productFromDb);
    // some other stuff
}

创建时product,内部调用Delta<TEntityType>构造函数,如下所示(无参构造函数也调用这个,传递typeof(TEntityType)

public Delta(Type entityType)
{
    this.Initialize(entityType);
}

Initialize方法看起来像这样

private void Initialize(Type entityType)
{
    // some argument validation, emitted for the sake of brevity 

    this._entity = (Activator.CreateInstance(entityType) as TEntityType);
    this._changedProperties = new HashSet<string>();
    this._entityType = entityType;
    this._propertiesThatExist = this.InitializePropertiesThatExist();
}

这里有趣的部分是this._propertiesThatExistDictionary<string, PropertyAccessor<TEntityType>>包含 Product 类型的属性。PropertyAccessor<TEntityType>是内部类型,以便更轻松地操作属性。

当你打电话时,product.Patch(productFromDb)这就是幕后发生的事情

// some argument checks
PropertyAccessor<TEntityType>[] array = (
        from s in this.GetChangedPropertyNames()
        select this._propertiesThatExist[s]).ToArray<PropertyAccessor<TEntityType>>();

    PropertyAccessor<TEntityType>[] array2 = array;

    for (int i = 0; i < array2.Length; i++)
    {
        PropertyAccessor<TEntityType> propertyAccessor = array2[i];
        propertyAccessor.Copy(this._entity, original);
    }

如您所见,它获取已更改的属性,对其进行迭代并将值从传递给 Patch 操作的实例设置为您从 db 获取的实例。因此,您传递的操作、要添加的属性名称和值不会反映任何内容。

propertyAccessor.Copy(this._entity, original)方法体

public void Copy(TEntityType from, TEntityType to)
{
    if (from == null)
    {
        throw Error.ArgumentNull("from");
    }
    if (to == null)
    {
        throw Error.ArgumentNull("to");
    }
    this.SetValue(to, this.GetValue(from));
}
于 2014-09-01T23:25:51.533 回答