Les deux entités sont une relation un-à-plusieurs (construite par le code first fluent api).
public class Parent
{
public Parent()
{
this.Children = new List<Child>();
}
public int Id { get; set; }
public virtual ICollection<Child> Children { get; set; }
}
public class Child
{
public int Id { get; set; }
public int ParentId { get; set; }
public string Data { get; set; }
}
Dans mon contrôleur WebApi, j'ai des actions pour créer une entité parente (qui fonctionne bien) et mettre à jour une entité parente (qui a un problème). L'action de mise à jour ressemble à ceci:
public void Update(UpdateParentModel model)
{
//what should be done here?
}
Actuellement, j'ai deux idées:
Obtenez une entité parent suivie nommée
existing
parmodel.Id
et attribuez des valeursmodel
une par une à l'entité. Cela semble stupide. Et dansmodel.Children
je ne sais pas quel enfant est nouveau, quel enfant est modifié (ou même supprimé).Créez une nouvelle entité parente via
model
, attachez-la au DbContext et enregistrez-la. Mais comment le DbContext peut-il connaître l'état des enfants (nouvel ajout / suppression / modification)?
Quelle est la bonne façon d'implémenter cette fonctionnalité?
la source
Réponses:
Étant donné que le modèle qui est publié sur le contrôleur WebApi est détaché de tout contexte de structure d'entité (EF), la seule option est de charger le graphique d'objet (parent, y compris ses enfants) à partir de la base de données et de comparer les enfants qui ont été ajoutés, supprimés ou actualisé. (À moins que vous ne suiviez les modifications avec votre propre mécanisme de suivi pendant l'état détaché (dans le navigateur ou ailleurs), ce qui à mon avis est plus complexe que ce qui suit.) Cela pourrait ressembler à ceci:
...CurrentValues.SetValues
peut prendre n'importe quel objet et mappe les valeurs de propriété à l'entité attachée en fonction du nom de la propriété. Si les noms de propriété de votre modèle sont différents des noms de l'entité, vous ne pouvez pas utiliser cette méthode et devez attribuer les valeurs une par une.la source
existingParent.Children.Add(newChild)
car alors la recherche existanteChild linq retournera l'entité récemment ajoutée, et donc cette entité sera mise à jour. Il vous suffit d'insérer dans une liste temporaire, puis d'ajouter.existingChild
demande un peu moins d'effort, consiste à modifier la clause where dans la requête LINQ:.Where(c => c.ID == childModel.ID && c.ID != default(int))
J'ai joué avec quelque chose comme ça ...
que vous pouvez appeler avec quelque chose comme:
Malheureusement, cela tombe en quelque sorte s'il y a des propriétés de collection sur le type enfant qui doivent également être mises à jour. Envisager d'essayer de résoudre cela en passant un IRepository (avec des méthodes CRUD de base) qui serait responsable d'appeler UpdateChildCollection seul. Appellerait le dépôt au lieu d'appels directs à DbContext.Entry.
Je n'ai aucune idée de la façon dont tout cela fonctionnera à grande échelle, mais je ne sais pas quoi faire d'autre avec ce problème.
la source
toAdd.ForEach(i => (selector(dbItem) as ICollection<Tchild>).Add(i.Value));
devrait résoudre le problème n -> n.Ok les gars. J'ai eu cette réponse une fois mais je l'ai perdue en cours de route. torture absolue quand vous savez qu'il existe un meilleur moyen mais que vous ne pouvez pas vous en souvenir ou le trouver! C'est très simple. Je viens de le tester de plusieurs façons.
Vous pouvez remplacer toute la liste par une nouvelle! Le code SQL supprimera et ajoutera des entités selon les besoins. Inutile de vous en préoccuper. Assurez-vous d'inclure la collection enfant ou pas de dés. Bonne chance!
la source
Si vous utilisez EntityFrameworkCore, vous pouvez effectuer les opérations suivantes dans l'action de publication de votre contrôleur (la méthode Attach attache de manière récursive les propriétés de navigation, y compris les collections):
On suppose que chaque entité qui a été mise à jour a toutes les propriétés définies et fournies dans les données de publication du client (par exemple, ne fonctionnera pas pour une mise à jour partielle d'une entité).
Vous devez également vous assurer que vous utilisez un nouveau contexte de base de données de structure d'entités dédié pour cette opération.
la source
C'est ainsi que j'ai résolu ce problème. De cette façon, EF sait lequel ajouter et lequel mettre à jour.
la source
Il existe quelques projets qui facilitent l'interaction entre le client et le serveur en ce qui concerne la sauvegarde d'un graphe d'objets entier.
En voici deux que vous voudriez examiner:
Les deux projets ci-dessus reconnaissent les entités déconnectées lorsqu'elles sont renvoyées au serveur, détectent et enregistrent les modifications et retournent aux données affectées par le client.
la source
Une simple preuve de concept
Controler.UpdateModel
ne fonctionnera pas correctement.Classe complète ici :
la source
@Charles McIntosh m'a vraiment donné la réponse à ma situation en ce que le modèle passé était détaché. Pour moi, ce qui a finalement fonctionné a été de sauvegarder d'abord le modèle passé ... puis de continuer à ajouter les enfants comme je l'étais déjà auparavant:
la source
Pour les développeurs VB.NET Utilisez ce sous générique pour marquer l'état enfant, facile à utiliser
la source
la source
la source
Voici mon code qui fonctionne très bien.
la source