2011-12-08 16 views
8

Ho un progetto MVC e utilizzo gli oggetti Entity Framework Code First e POCO per il database. Ad esempio:Come aggiornare le entità correlate in Entity Framework

Ho un ActionResult che crea o modifica un modello. Il problema è quando chiamo ActionResult per aggiornare il modello e model.B è stato modificato, la relazione non è stata salvata nel database. Quando viene chiamato ActionResult per creare un nuovo oggetto, funziona come previsto. Come lo risolvo?

public ActionResult Save(ClassA model) 
{ 
    model.B = GetBFromDb(model.B.Id.Value); 

    if(ModelState.IsValid) 
    { 
    if (id.HasValue) 
    { 
     context.Entry(model).State = System.Data.EntityState.Modified; 
    } 
    else 
    { 
     context.ClassAs.Add(model); 
    } 
    context.SaveChanges(); 
    // redirect to index etc. 
    } 
    return View("EditForm", model); 
} 

risposta

3

ho risolto modificando ClassA con una chiave esterna per ClassB, e impostando il valore di BId:

public class ClassA 
{ 
    public int? Id {get; set;} 
    public string Name { get; set;} 
    public int BId {get;set;} // foreign key to B 
    public virtual ClassB B {get; set;} 
} 

Perchè questa proprietà chiave esterna fa il lavoro al posto del ky estera generato di EF?

+3

in modalità disconnessa, quando non si dispone di una chiave esterna ci sono alcuni vuoti che EF non può aggirare e devi provare un codice extra. Altrimenti non può vedere la relazione. Con la proprietà FK, è un valore scalare e più facile per EF tenere traccia di tutti i processi. In realtà ho scritto la mia colonna dei punti dati gen 2012 su questo argomento esatto! EF è molto più facile da usare quando si ha una proprietà scalare FK. Altrimenti molte funzioni che ti aspetti di "solo lavorare" non possono obbligarti a capire meglio cosa sta succedendo e come fornire le informazioni necessarie. Scusa se non ho visto l'FK mancante prima di –

+0

@JulieLerman, nessun problema, grazie per il tuo aiuto! :) – Marthijn

2

Non si può semplicemente chiamare:

context.Entry(model).State = System.Data.EntityState.Modified; 

L'entità deve essere recuperato dal contesto prima in modo che EF può iniziare a monitorare esso. Quindi dovrai applicare eventuali modifiche a quell'entità prima di chiamare context.SaveChanges().

var entity = context.ClassAs.Find(model.Id); 

// set properties you want to modify on entity 
entity.Name = model.Name; 
entity.ClassB = context.ClassBs.Find(model.ClassB.Id); 
// other changes to entity as required... 

context.SaveChanges(); 

In questo modo EF sta rintracciando entity e sa applicare un aggiornamento contro di essa.

+0

Grazie funziona! E come imposto 'entity.ClassB = null;'? Sembra che impostarlo su null non funzioni. – Marthijn

+1

Yuck ... context.Entry (model) .State farà in modo che il contesto veda se il modello viene tracciato e, in caso contrario, inizierà a seguirlo. Non è necessario eseguire un'altra query db per ottenere il tracciamento dell'istanza del modello. Il problema con cui Henkie sta avendo quell'angolo è che Entry quel metodo cambierà solo per impostare lo stato dell'entità passata. L'impostazione dello stato "modificato" non sarà applicata al resto del grafico. –

+0

@JulieLerman Grazie ho trovato alcuni tutorial che impostano anche lo stato su modificato. Ma poi ho ancora il problema che i miei rapporti non si aggiorneranno. – Marthijn

0

Se si allega e si imposta lo stato sull'entità modificata, il framework invierà tutte le proprietà per l'aggiornamento. Non devi prendere l'approccio della lontra qui di seguito, perché ciò provoca un intero carico separato. Se lo fai in quel modo non ha senso passare in un modello, solo un id e poi chiama TryUpdateModel per riempire le proprietà dal modulo.

Personalmente l'attaccatura come modificato qui è un po 'più pulito in quanto non necessita di un giro completo a causa del caricamento dei dati

http://geekswithblogs.net/michelotti/archive/2009/11/27/attaching-modified-entities-in-ef-4.aspx

Problemi correlati