Insert objects into OData with the required foreign keys

EDIT-2: After several hours of research and almost every google-related google link that turned purple, I found out that the concept of "deep inserts" () exists in the OData specification. Therefore, in the end, what I am doing should work, even without links. Does anyone know how to enable this on a Microsoft OData client? Are there any other OData clients supporting this concept?

EDIT: Maybe this is the wrong approach, so please tell me if I am not doing this completely wrong. The inability to save really blocks our progress!

I have a problem with OData v3. I have an Associate class that has the required Address . When I try to POST the new helper, it fails because the Address property is null (EF6 throws a DbUpdateException with a foreign key violation). My Associate class is as follows:

 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 am using the Microsoft OData client and trying to add an associated element as follows:

 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 assistant comes without a foreign key. When I test a POST request with Fiddler, I understand 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, although the generated class on the client has the Address property.

How can I solve this problem?

+5
source share
4 answers

There is no solution. I will flip my own context with the concept of change sets that works with web-api. I'll put it on github when we're done.

0
source

I also could not find any information about this - it really looks like a problem in OData. Here's how I managed to get it to work.

Define a foreign key explicitly

 class Student { public int TeacherId { get; set; } [Required, ForeignKey("TeacherId")] public virtual Teacher Teacher { get; set; } } 

When performing an insert, select the appropriate entry and correct the state of the model:

  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 now on, to send the student, you ignore the "Teacher" field and simply publish with TeacherId.

I have not tested this with the OData client, but I cannot figure out why this will not work. You just need to use the Id field, not the object.

+1
source

Mostly when creating an object

 var associate = new Associate { /* ... */ }; 

It is not inserted into the database. It is created in memory. When you call

 context.SaveChanges(); 

It will be saved in the database. At this stage, the database is checked and keys are generated. Assuming your identifier is a unique identifier that is generated in the database date, note that in order to get the updated value from the database, you need StoreGeneratedPattern to set the Identity from the Entity model view.

If this is not done, your local context and the database context no longer match. If you where to use this object with a link to something else, it will not work.

I assume something like this will work:

 Address address = new Address{ City = "Tallinn" /*etc*/}; context.SaveChanges(); //At this point Address will be in database context and has Id associate = new Associate { name = "Margus", role = "Admin", receiver = true, representative = true, AddressId = address.id }; context.SaveChanges(); 
0
source

The only way to work with addlink and setlink is that the foreign key is NULL and you want to create a post operation call creation link, see here

0
source

Source: https://habr.com/ru/post/1212794/


All Articles