7

J'ai été frustré par cela pour un jour ... s'il vous plaît aider. J'ai une section de facture dans laquelle je suis capable d'ajouter dynamiquement de nouveaux éléments en ajoutant/supprimant des éléments DOM en utilisant JQuery ... j'ai déjà compris comment nommer ces éléments correctement afin qu'ils soient par conséquent correctement mappés le modèle et envoyer au paramètre d'action.ASP.NET MVC 3 EF CodeFirst - édition d'article DBContext

Alors disons que j'ai une action dans mon contrôleur appelé Edition avec le paramètre de type facture

[HttpPost] 
public virtual ActionResult Edit(Invoice invoice) { 
    if (ModelState.IsValid) { 
     //code discussed below 
    } 
    return RedirectToAction("Index"); 
} 

Le paramètre de facture contient toutes les données que je veux. Je n'ai pas de problème avec ça. Ce qui suit est le modèle d'objet.

public class Invoice 
{ 
    [Key] 
    public int ID { get; set; } 
    public InvoiceType InvoiceType { get; set; } 
    public string Description { get; set; } 
    public int Amount { get; set; } 
    public virtual ICollection<InvoiceItem> InvoiceItems { get; set; } 
} 

Notez le InvoiceItems collection - il contient une collection des éléments de facture insérés dynamiquement. Ce qui suit est le modèle InvoiceItem

[Table("InvoiceItems")] 
public class InvoiceItem 
{ 
    [Key] 
    public int ID { get; set; } 

    [ForeignKey("Invoice")] 
    public int InvoiceID { get; set; } 
    public Invoice Invoice { get; set; } 

    public string Description { get; set; } 
    public int Amount { get; set; } 
} 

Et c'est là que je suis coincé.

Je ne peux pas insérer/mettre à jour les éléments de la collection Factures InvoiceItems dans la base de données par hasard. J'ai beaucoup cherché sur google et j'ai trouvé ces solutions - aucune de ces solutions ne fonctionne malheureusement.

Solution # 1 - un code bizarre avec SetValues:

Invoice origInvoice = db.Invoices.Single(x => x.ID == invoice.ID); 
var entry = db.Entry(origInvoice); 
entry.OriginalValues.SetValues(invoice); 
entry.CurrentValues.SetValues(invoice); 
db.SaveChanges(); 

Solution # 2 - l'ajout d'une nouvelle méthode de mise à jour à mon DbContext:

public void Update<T>(T entity) where T : class 
{ 
    this.Set<T>().Attach(entity); 
    base.ObjectContext.ObjectStateManager.ChangeObjectState(entity,System.Data.EntityState.Modified); 
} 

Solution # 3 - attacher une entité existante mais modifiée au contexte selon http://blogs.msdn.com/b/adonet/archive/2011/01/29/using-dbcontext-in-ef-feature-ctp5-part-4-add-attach-and-entity-states.aspx

db.Entry(invoice).State = EntityState.Modified; 
db.SaveChanges(); 

Comment solution # 1 œuvres: mises à jour toutes les propriétés à l'exception InvoiceItems nouvellement ajoutés. SetValues ​​() ignore la propriété ICollection. Cela fonctionnerait si j'ajoutais cette ligne juste avant db.SaveChanges();

origEntry.Entity.InvoiceItems = invoice.InvoiceItems; 

... mais je ne crois pas que ce soit la bonne approche.

Fonctionnement de la solution 2: ne fonctionne pas du tout car il n'existe aucune propriété ObjectContext dans la classe DbContext.

Comment la solution 3 fonctionne: cette solution mettra à jour la facture, mais ignorera sinon InvoiceItems.


Informations complémentaires: Ce qui suit est le morceau de javascript qui est utilisé pour générer les éléments d'éléments qui sont mis en correspondance avec les propriétés de InvoiceItem.La dernière question: qu'est-ce que je fais mal? Quel est le problème d'avoir une nouvelle collection d'éléments par rapport à un autre modèle automatiquement inséré dans la base de données? Pourquoi est-il ignoré, lorsque le modèle parent est mis à jour avec succès?

Edit 1: corrections

+0

Lorsque vous dites "impossible d'ajouter les éléments", qu'est-ce que cela signifie exactement? Cela signifie-t-il qu'une exception est générée? Si oui, quelle est l'exception? –

+0

Oui, pouvez-vous s'il vous plaît signaler l'exception? – Jack

Répondre

6

DbEntityEntry.CurrentValues.SetValues met à jour uniquement des propriétés scalaires et complexes. Il ne se soucie pas des propriétés de navigation. C'est la raison pour laquelle les modifications de votre collection InvoiceItems ne sont pas écrites dans la base de données. Le même problème consiste à définir l'état du Invoice sur Modified. Cela ne marque que les propriétés scalaires et complexes telles que modifiées, mais pas les propriétés de navigation. Malheureusement EF ne propose pas une méthode simple qui analyserait pour vous quels éléments d'une collection de navigation ont été ajoutés, supprimés ou seulement modifiés par rapport à l'état d'origine dans la base de données si les changements ont été effectués pendant que les entités étaient détaché d'un contexte (sur une page web dans votre exemple). Cela signifie que vous devez effectuer cette comparaison entre l'état d'origine dans la base de données et le nouvel état modifié vous-même.

exemples de code comment faire qui sont dans les réponses ici par exemple: The relationship could not be changed because one or more of the foreign-key properties is non-nullable Les exemples correspondent assez bien à votre situation, il suffit de remplacer ParentItem par Invoice et ChildItems par InvoiceItems.

Vous pouvez également jeter un oeil à cette question il y a quelques jours pour des infos supplémentaires: WCF, Entity Framework 4.1 and Entity's State Il y a beaucoup d'autres questions qui concernent le même problème que le manque de support pour la mise à jour des graphes d'objets détachés (qui est un scénario assez commun) est l'une des limitations les plus désagréables d'Entity Framework.

(Une remarque: dans un contrôleur MVC, il y a la méthode UpdateModel Je ne sais pas si cette méthode est capable de mettre à jour un graphe d'objet complet (ajouter, supprimer et modifier des éléments dans une collection). Je ne l'utilise pas, et je ne l'utiliserais pas pour travailler avec le modèle DB, juste pour les mises à jour ViewModel.)

+0

Merci, c'est l'information dont j'avais besoin :) – Mirek

Questions connexes