Mistake. Cannot apply PATCH to navigation property. So what should I do?
I have a Web API 2.2 OData 4 serving the following model using entity framework:
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; }
}
And a little bit of smooth display:
modelBuilder.Entity<Company>().HasMany(x => x.CompanyTypes).WithMany(x => x.Companies).Map(x =>
{
x.MapLeftKey("CompanyId");
x.MapRightKey("CompanyTypeId");
x.ToTable("CompaniesCompanyTypes");
});
On my CompanysController I have a patch method and I hope you can submit the following request and successfully update the company name and create a couple of company type records for that company:
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"}]}
But I am getting:
{
"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":""
}
}
}
I am guessing that I am asking too much of my PATCH request, but does anyone have any suggestion on how I should achieve this? The simpler the better - I don't want to add complexity to my client application if I can avoid it, and would rather use PATCH over PUT.
Many thanks. If you are interested in this question and would like more information, please ask.
EDIT
Specifically, what I need is the ability to insert a record into many tables when a record is updated on a portion of that relationship. For example. If a Student has many classes and a class has many students, then when I update Student A, I can also add the link to Class One, remove the link to the second class, and leave the link to the third class.
I read the OData documentation here:
But for me this is a bit of a mystery. I'm sure there must be a way to do this using things like "@ odata.bind" etc.
Any opinions there?
source to share
Based on this workitem , you need to create a collection of primitive types instead of a complex list type.
Entity
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; }
}
Act
// 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
}
Config
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Product>("Products");
builder.EntitySet<ProductDto>("ProductDtos");
builder.EntitySet<ProductType>("ProductType");
config.Routes.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());
Violinist
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
Hope it helps.
source to share