2015-02-06 4 views
5

EDIT-2: Nach Stunden der Forschung und fast jeder odata bezogenen Link auf Google drehen lila, fand ich heraus, dass das Konzept der 'Deep-Einsätze' (link) existiert in der OData-Spezifikation. Also, was ich mache, sollte auch funktionieren, auch ohne die Links. Kann jemand das auf dem Microsoft OData-Client aktivieren? Gibt es andere OData-Kunden, die dieses Konzept unterstützen?Einfügen von Entities in OData mit erforderlichen Fremdschlüssel

EDIT: Vielleicht ist dies der falsche Ansatz, also bitte sagen Sie mir, wenn ich es total falsch mache. Nicht speichern zu können, blockiert wirklich unseren Fortschritt!

Ich habe ein Problem mit OData v3. Ich habe eine Klasse Associate, die eine erforderliche Address hat. Wenn ich versuche, einen neuen Associate zu senden, schlägt es fehl, da die Address-Eigenschaft null ist (EF6 löst DbUpdateException mit Fremdschlüsselverletzung aus). Meine Associate Klasse sieht wie folgt aus:

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; } 
} 

ich mit dem Microsoft OData-Client, und versuche, die Mitarbeiter in der folgenden Art und Weise hinzuzufügen:

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 

auf dem Server in der Steuerung, die Associate ankommt ohne den Fremdschlüssel jedoch. Wenn ich die POST-Anfrage mit Fiddler überprüfen, sehe ich, warum:

{ 
    "odata.type" : "xxx.Data.Entities.Associate", 
    "AddressId" : 0, 
    "Id" : 0, 
    "IsLegalRepresentative" : false, 
    "IsMailReceiver" : false, 
    "Name" : "John Doe", 
    "Role" : "Father" 
} 

Die Adresse nicht übertragen wird, auch wenn die erzeugte Klasse auf dem Client eine Address Eigenschaft hat.

Wie kann ich dieses Problem lösen?

+0

siehe erstellen Haben Sie das Entity Framework-Modell richtig eingerichtet, um die AddressId Eigenschaft auf die Krawatte Adresseinheit? Oft vergesse ich das, damit meine Eigenschaft nicht korrekt mit dem Fremdschlüssel verknüpft wird. –

+0

@TheSenator Die Adresse ist auch neu, deshalb brauche ich das materialisierte Objekt auf der Serverseite, damit EF den Rest verwalten kann (wie es so gut geht). – LueTm

+0

Wie senden Sie die JSON POST-Anfrage vom Client? Genauer gesagt, wie wird die Associate/Address auf der Client-Seite serialisiert? – nXu

Antwort

0

Es gibt keine Lösung für dieses Problem. Ich werde meinen eigenen Kontext mit einer Vorstellung von Changesets rollen, die mit Web-API funktioniert. Ich werde es auf Github setzen, wenn ich fertig bin.

0

Grundsätzlich, wenn Sie erstellen das Objekt

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

Es wird nicht in die Datenbank eingefügt. Es wird im Speicher erstellt. Wenn Sie anrufen

context.SaveChanges(); 

Es wird in der Datenbank gespeichert werden. An diesem Punkt passiert die Validierung der Datenbank und Schlüssel werden generiert. Angenommen, Ihre ID ist ein eindeutiger Bezeichner, der in der Datenbank generiert wird. Beachten Sie, dass StoreGeneratedPattern auf Identity von Entity-Modellansicht festgelegt werden muss, damit der Wert von der Datenbank aktualisiert wird.

Wenn dies nicht erfolgt, stimmen der lokale Kontext und der Datenbankkontext nicht mehr überein. Wenn Sie dieses Objekt mit Bezug auf etwas anderes verwenden möchten, würde es fehlschlagen.

Ich nehme so etwas wie dies funktionieren würde:

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

Wenn Sie ein Handbuch benötigen, dann: https://msdn.microsoft.com/en-us/data/jj713564.aspx – Margus

+0

Sie sagen also, ich muss alle neuen Entitäten zuerst POST? Dies wäre sehr kompliziert. Ich müsste herausfinden, welche neuen Entitäten von anderen neuen abhängen, sie dann in dieser Reihenfolge an den Server senden, dann die IDs zurückholen, sie zuweisen, alle Objekte erneut aktualisieren und dann die Speicheränderungen im OData-Kontext aufrufen. Ist das wirklich so? Scheint so, als würde ich einen OData-Kontext selbst so kodieren:/ – LueTm

+0

@LueTm Nein, aber höchstwahrscheinlich hast du ein Problem und es wird dir helfen, herauszufinden, was es ist, während du die Möglichkeiten eliminierst. – Margus

1

Auch ich konnte keine Informationen darüber finden - es fühlt sich wirklich wie ein Problem in OData an. Hier ist, wie ich es geschafft habe, es zum Laufen zu bringen.

Definieren Sie den Fremdschlüssel explizit

class Student { 
     public int TeacherId { get; set; } 

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

Wenn der Einsatz durchgeführt wird, holen den verknüpften Datensatz und fixieren den Modellzustand:

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); 
     } 
    } 

Also von da an einen Schüler zu schreiben, Sie ignorieren die Lehrerfeld und poste einfach mit TeacherId.

Ich habe dies nicht mit dem OData-Client getestet, aber ich kann mir nicht vorstellen, warum das nicht funktionieren würde. Sie müssen nur das Id-Feld und nicht das Objekt verwenden.

0

Der einzige Weg, addlink und SetLink Arbeit ist, wenn der Fremdschlüssel NULL-Werte zulässt und Sie ahvbe einen postput Funktionsaufruf erstellen Link here

Verwandte Themen