2015-02-06 8 views
5

EDIT-2: Dopo ore di ricerca e di quasi tutti i link correlati odata su google girando viola, ho scoperto che il concetto di 'Deep-inserti' (link) esiste nel Specifica OData. Quindi, dopo tutto, quello che sto facendo dovrebbe funzionare, anche senza i collegamenti. Qualcuno sa come abilitarlo sul client Microsoft OData? Ci sono altri client OData che supportano questo concetto?Inserimento di entità in OData con richieste chiavi esterne

MODIFICA: Forse questo è l'approccio sbagliato, quindi per favore dimmi se lo sto facendo completamente sbagliato. Non essere in grado di salvare blocca davvero i nostri progressi!

Ho un problema con OData v3. Ho una classe Associate che ha un numero richiesto Address. Quando provo a POST un nuovo Associato, fallisce a causa della proprietà Address null (EF6 lancia DbUpdateException con violazione di chiave esterna). La mia classe Associate si presenta così:

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

Io uso il client Microsoft OData, e tenta di aggiungere il socio nel seguente modo:

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 

Sul server, nel controller, l'Associate arriva senza la chiave esterna, tuttavia. Quando ho ispezionare la richiesta POST con Fiddler, ho capire perché:

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

L'indirizzo non viene trasmesso, anche se la classe generata sul client ha una proprietà Address.

Come posso risolvere questo problema?

+0

Avete configurare il modello Entity Framework per legare correttamente la proprietà AddressId al Indirizzo entità? Spesso mi dimentico di farlo, quindi la mia proprietà non si collega correttamente alla chiave esterna. –

+0

@TheSenator Anche l'indirizzo è nuovo, ecco perché ho bisogno dell'oggetto materializzato sul lato server, quindi EF può gestire il resto (come fa così bene). – LueTm

+0

Come si invia la richiesta POST JSON dal client? Più esattamente, come serializzi l'indirizzo/associato sul lato client? – nXu

risposta

0

non esiste una soluzione a questo. Creerò il mio contesto con una nozione di serie di modifiche che funziona con il web-api. Lo metterò su Github, quando ho finito.

0

Fondamentalmente, quando si crea l'oggetto

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

Non è inserito nel database. È creato nella memoria. Quando chiami

context.SaveChanges(); 

Sarà salvato nel database. A questo punto avviene la convalida del database e vengono generate le chiavi. Supponendo che l'ID sia un identificatore univoco, generato nella base dati, si noti che per ottenere il valore aggiornato dal database è necessario avere StoreGeneratedPattern impostato su Identità dalla visualizzazione modello Entity.

Se ciò non avviene, il contesto locale e il contesto del database non corrispondono più. Se tu dovessi usare quell'oggetto con riferimento a qualcos'altro, fallirebbe.

presumo qualcosa di simile a questo dovrebbe funzionare:

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

Se hai bisogno di un manuale, allora: https://msdn.microsoft.com/en-us/data/jj713564.aspx – Margus

+0

Quindi stai dicendo che devo POSTARE tutte le nuove entità prima? Questo sarebbe molto complicato. Avrei bisogno di capire quali nuove entità dipendono da altre nuove, poi le POST sul server in quell'ordine, poi recuperare gli ID, assegnarli, aggiornare di nuovo tutti gli oggetti e poi chiamare save changes nel contesto OData. È davvero così? Sembra che sto codificando un contesto OData in questo modo:/ – LueTm

+0

@LueTm No, ma molto probabilmente hai un problema e ti aiuterà a capire di cosa si tratta eliminando le possibilità. – Margus

1

Anche io non sono riuscito a trovare alcuna informazione al riguardo - sembra davvero un problema in OData. Ecco come sono riuscito a farlo funzionare.

Definire la chiave esterna esplicitamente

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

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

Quando si esegue l'inserto, prendere il record correlato e fissare il modello di stato:

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

Quindi, da quel momento in poi per postare uno Studente, si ignora il Campo insegnante e basta pubblicare con TeacherId.

Non l'ho provato con il client OData, ma non riesco a pensare al motivo per cui questo non funzionerebbe. Dovrai solo usare il campo Id piuttosto che l'oggetto.

0

L'unico AddLink modo e lavorare SetLink è se la chiave esterna è annullabile e si ahvbe per creare una chiamata di funzione postput creare un link vedi here

Problemi correlati