错误:无法将PATCH应用于导航属性。那我该怎么办?

时间:2014-09-11 15:12:38

标签: c# odata asp.net-web-api2

我有一个使用实体框架的Web API 2.2 OData 4服务以下模型:

public class Company
{
  public int Id { get; set; }
  public string Name { get; set; }
  public virtual ICollection<CompanyType> CompanyTypes { get; set; }
}

public class CompanyType
{
  public int Id { get; set; }
  public string Name { get; set; }
  public virtual ICollection<Company> Companies { get; set; }
}

还有一点流畅的映射:

modelBuilder.Entity<Company>().HasMany(x => x.CompanyTypes).WithMany(x => x.Companies).Map(x =>
{
  x.MapLeftKey("CompanyId");
  x.MapRightKey("CompanyTypeId");
  x.ToTable("CompaniesCompanyTypes");
});

在我的CompanysController上我有一个补丁方法,并希望能够发送以下请求并成功更新公司名称并为该公司创建几个公司类型记录:

PATCH http://localhost:50113/MessagingService/odata//CompanyDTOs(1)/ HTTP/1.1
Accept: application/json
Content-Type: application/json; charset=utf-16
Host: localhost:50113
Content-Length: 174

{"Name":"Cheesy Peas Ltd","CompanyTypes":[{"Id":1,"Name":"Parent"},{"Id":2,"Name":"Subsidiary"}]}

但我收到了:

{
  "error":{
    "code":"","message":"The request is invalid.","innererror":{
      "message":"delta : Cannot apply PATCH to navigation property 'CompanyTypes' on entity type 'Core.Models.Company'.\r\n","type":"","stacktrace":""
    }
  }
}

我认为我过多地询问了我的PATCH请求,但是有人建议我应该如何实现这个目标吗?越简单越好 - 如果我可以避免它,并且更愿意使用PATCH而不是那个PUT,我不热衷于为我的客户端应用程序添加复杂性。

非常感谢。如果您对此问题感兴趣并需要更多详细信息,请询问。

修改

具体来说,我所追求的是在更新该关系的一部分中的记录时能够在多对多表中插入记录。例如。如果学生有很多课程且课程有很多学生,那么当我更新学生A时,我可能还想添加对第一课的引用,删除对第二课的引用并保留对第三类的引用。

我已经在这里阅读了OData文档:

http://docs.oasis-open.org/odata/odata-atom-format/v4.0/cs02/odata-atom-format-v4.0-cs02.html#_Toc372792732

但这对我来说有点神秘。我确信必须有一种方法可以使用像&#34; @ odata.bind&#34;这样的东西。等

有任何意见吗?

1 个答案:

答案 0 :(得分:4)

基于this workitem,您需要创建一组基本类型而不是列表复杂类型。

<强>实体

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public ICollection<ProductType> ProductTypes { get; set; }
}
public class ProductDto : Product
{
    public ICollection<int> ProductTypeIds { get; set; }
    public ICollection<string> ProductTypeNames { get; set; }
}
public class ProductType
{
    public int Id { get; set; }
    public string Name { get; set; }
}

<强>动作

// PATCH odata/Products(5)
[AcceptVerbs("PATCH", "MERGE")]
public IHttpActionResult Patch([FromODataUri] int key, Delta<ProductDto> patch)
{
    object productTypeIds;
    patch.TryGetPropertyValue("ProductTypeIds", out productTypeIds);
    object productTypeNames;
    patch.TryGetPropertyValue("ProductTypeNames", out productTypeNames);

    // TODO: Implement update to database.

    return Updated(new ProductDto()); // for demo purpose
}

<强>配置

ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Product>("Products");
builder.EntitySet<ProductDto>("ProductDtos");
builder.EntitySet<ProductType>("ProductType");
config.Routes.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());

<强>的Fiddler

PATCH http://localhost:59829/odata/Products(1) HTTP/1.1

User-Agent: Fiddler
Host: localhost:59829
Content-Length: 83
Content-Type: application/json

{"Id":1, "Name":"A", "ProductTypeIds":[1,2], "ProductTypeNames":["AA", "BB"] }

<强>结果

Result

希望有所帮助。