EDIT-2: After hours of research and almost every odata related link on google turning purple, I found out that the concept of 'deep-inserts' (link) exists in the OData specification. So after all, what I'm doing should work, even without the links. Does anyone know how to enable this on the Microsoft OData client? Are there any other OData clients out there that support that concept?
EDIT: Maybe this is the wrong approach, so please tell me if I'm doing it totally wrong. Not being able to save is really blocking our progress!
I have an issue with OData v3. I have a class Associate
that has a required Address
. When I try to POST a new Associate, it fails due to the Address
property being null (EF6 throws DbUpdateException with foreign key violation). My Associate
class looks like this:
public class Associate
{
public int Id { get; set; }
[Required, StringLength(100)]
public string Name { get; set; }
[Required, StringLength(50)]
public string Role { get; set; }
public bool IsMailReceiver { get; set; }
public bool IsLegalRepresentative { get; set; }
[ForeignKey("AddressId")]
public virtual Address Address { get; set; }
public int AddressId { get; set; }
}
I use the Microsoft OData client, and try to add the associate in the following way:
var associate = new Associate { /* ... */ };
context.AddObject("Associates", associate);
context.AddObject("Addresses", associate.Address);
/* UI fills associate data */
context.SetLink(associate, "Address", associate.Address);
context.UpdateObject(associate);
context.UpdateObject(associate.Address);
/* at this point the associate has the address set! */
context.SaveChanges(); // << Exception
On the server, in the controller, the Associate arrives without the foreign key, however. When I inspect the POST request with Fiddler, I see why:
{
"odata.type" : "xxx.Data.Entities.Associate",
"AddressId" : 0,
"Id" : 0,
"IsLegalRepresentative" : false,
"IsMailReceiver" : false,
"Name" : "John Doe",
"Role" : "Father"
}
The address is not transmitted, even though the generated class on the client has an Address
property.
How can i solve this problem?
I too could not find any information about this - it really feels like an issue in OData. Here is how I managed to get it to work.
Define the foreign key explicitly
class Student {
public int TeacherId { get; set; }
[Required, ForeignKey("TeacherId")]
public virtual Teacher Teacher { get; set; }
}
When performing the insert, fetch the related record and fix the model state:
public IHttpActionResult Post(Student student)
{
student.Teacher = this.db.Teacher.FirstOrDefault(i => i.TeacherId == student.TeacherId);
if (student.Teacher != null)
{
this.ModelState.Remove("student.Teacher");
}
if (!this.ModelState.IsValid)
{
return this.BadRequest(this.ModelState);
}
}
So from then on to post a Student, you ignore the Teacher field and just post with TeacherId.
I haven't tested this with the OData client, but I can't think of why this wouldn't work. You will just have to use the Id field rather than the object.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With