我有一个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文档:
但这对我来说有点神秘.我确信必须有一种方法可以使用“@ odata.bind”之类的东西.
有什么意见吗?
解决方法:
基于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());
提琴手
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"] }
结果
希望有所帮助.