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

use*_*071 6 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; }
}
Run Code Online (Sandbox Code Playgroud)

还有一些流畅的映射:

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

在我的 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"}]}
Run Code Online (Sandbox Code Playgroud)

但我收到一个:

{
  "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":""
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我认为我对 PATCH 请求的要求太多了,但是有人对我应该如何实现这一目标提出建议吗?越简单越好 - 如果可以避免的话,我并不热衷于增加客户端应用程序的复杂性,并且更喜欢使用 PATCH 而不是 PUT。

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

编辑

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

我在这里阅读了一些 OData 文档:

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

但这对我来说有点神秘。我确信必须有一种方法可以使用“@odata.bind”之类的东西来做到这一点。

有什么意见吗?

Yul*_*dra 4

基于此工作项,您需要创建原始类型的集合而不是列表复杂类型。

实体

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; }
}
Run Code Online (Sandbox Code Playgroud)

行动

// 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
}
Run Code Online (Sandbox Code Playgroud)

配置

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

提琴手

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"] }
Run Code Online (Sandbox Code Playgroud)

结果

结果

希望有帮助。