2010-06-08 4 views
2

J'ai trouvé beaucoup de questions ici sur SO et des articles partout sur Internet, mais aucun n'a vraiment abordé mon problème.Entity Framework - Mettre à jour des entités sans Id

Mon modèle ressemble à ceci (je rayé toutes les propriétés non essentielles): alt text http://i47.tinypic.com/244p6qh.jpg

Tous les jours ou si « Play » est mis à jour (via un fichier XML contenant les informations).

internal Play ParsePlayInfo(XDocument doc) 
{ 
    Play play = (from p in doc.Descendants("Play") 
    select new Play 
    { 
     Theatre = new Theatre() 
     { 
      //Properties 
     }, 
     //Properties 
     LastUpdate = DateTime.Now 
    }).SingleOrDefault(); 

    var actors = (from a in doc.XPathSelectElement(".//Play//Actors").Nodes() 
    select new Lecturer() 
    { 
     //Properties 
    }); 

    var parts = (from p in doc.XPathSelectElement(".//Play//Parts").Nodes() 
    select new Part() 
    { 
     //Properties 
    }).ToList(); 

    foreach (var item in parts) 
    { 
     play.Parts.Add(item); 
    } 

    var reviews = (from r in doc.XPathSelectElement(".//Play//Reviews").Nodes() 
    select new Review 
    { 
     //Properties 
    }).ToList(); 

    for (int i = 0; i < reviews.Count(); i++) 
    { 
     PlayReviews pR = new PlayReviews() 
     { 
      Review = reviews[i], 
      Play = play, 
      //Properties 
     }; 
     play.PlayReviews.Add(pR); 
    } 
    return play; 
} 

Si j'ajoute ce « jeu » via Ajouter() tous les ChildObject de jeu sera inséré - peu importe si certains existent déjà. Puisque j'ai besoin de mettre à jour des entrées existantes, je dois faire quelque chose à ce sujet. Je suppose que le problème ici est que je n'ai aucun Id dans le XML que ce soit.

Pour autant que je peux dire que j'ai les options suivantes:

  1. ajouter/mettre à jour les entités enfant dans mes PlayRepositories Add-Méthode
  2. restructuration et récrire ParsePlayInfo() pour obtenir toutes les entités enfant d'abord, ajouter ou mettre à jour eux et puis créer un nouveau jeu. Le seul problème que j'ai ici est que je voulais ParsePlayInfo() pour être persistance ignorant, je pouvais travailler autour de ce par
  3. création de plusieurs méthodes parse (par exemple ParseActors()) et les affecter à jouer dans mon contrôleur (j'utilise ASP.net MVC) après tout a été analysé et ajouté

Actuellement, je suis l'option 1 de mise en œuvre - mais il se sent mal.

Ce que je veux faire est de mettre à jour les entités qui sont déjà dans la base de données et d'en insérer de nouvelles qui ne le sont pas. Dois-je appeler SaveChanges() avant de joindre/ajouter un jeu? Il doit y avoir une solution (relativement) facile. J'apprécierais que quelqu'un puisse me guider dans la bonne direction sur celui-ci.

Répondre

1

Eh bien, puisqu'il n'y a pas encore de réponse, j'en écrirai moi-même. Pour ceux qui se demandent, je me suis mis au travail - le code a l'air horrible et je suppose que la performance est encore pire. Mais comme il n'y aura pas beaucoup d'utilisateurs et cette méthode ne sera appelée qu'une fois par jour la nuit de toute façon je vais bien pour le moment.

Qu'est-ce que j'ai fait?

Eh bien, je suis allé avec l'option 2 et 3.

private Play UpdatePlay() 
{ 
    using (RepositoryContext context = new RepositoryContext()) 
    { 
     HttpRequest http = new HttpRequest(); 
     PlayRepository rep = new PlayRepository(context); 

     ActorRepository actRep = new ActorRepository(context); 
    ReviewsRepository revRep = new ReviewsRepository(context); 
     TheatreRepository insRep = new TheatreRepository(context); 
     PartRepository partRep = new PartRepository(context); 

     Parser p = new Parser(); 

     XDocument doc = http.GetPlayInfo(); 

     Theatre theatre = p.ParseTheatreInfo(doc); 
     List<Actor> actors = p.ParseActorInfo(doc); 
     List<PlayReviews> playReviews = p.ParseReviewsInfo(doc); 

     for (int i = 0; i < actors.Count; i++) 
     { 
      actors[i] = actRep.AddOrUpdate(actors[i]); 
     } 
     for (int i = 0; i < playReviews.Count; i++) 
     { 
      playReviews[i].Reviews = revRep.AddOrUpdate(playReviews[i].Reviews); 
     } 

     theatre = insRep.AddOrUpdate(theatre); 

     Play play = p.ParsePlayInfo(doc); 

     List<Part> parts = GetParts(play); 

     for (int i = 0; i < parts.Count; i++) 
     { 
      List<Actor> lec = (List<Actor>)parts[i].Actors; 
      for (int j = 0; j < lec.Count; j++) 
      { 
       lec[j] = actRep.AddOrUpdate(lec[j]); 
      } 

     } 

     play = rep.AddOrUpdate(play); 
     context.LoadProperty(play, o => o.Theatre); 
     context.LoadProperty(play, o => o.Actors); 
     context.LoadProperty(play, o => o.PlayReviewss); 
     context.LoadProperty(play, o => o.Parts); 

     rep.Save(); 

     if (play.Theatre != theatre) 
      play.Theatre = theatre; 

     play = rep.AddParts(parts, play); 

     play = rep.AddActor(actors, play); 

     for (int i = 0; i < playReviews.Count; i++) 
     { 
      playReviews[i].Play = play; 
      playReviews[i] = revRep.AddPlayInformation(playReviews[i]); 
     } 

     rep.Save(); 
     return play; 
    } 
} 

(Et sur une note de côté, je viens de réaliser que j'ai oublié auparavant pour poster cette partie de mon code ...)

comme vous pouvez le voir, Save() est appelée deux fois - et il y a pire quand on considère ce qui se passe dans AddOrUpdate():

public Actor AddOrUpdate(Actor entity) 
{ 
    Actor cur = context.Actors.Where(l => l.Name == entity.Name && l.Last_Name == entity.Last_Name).FirstOrDefault(); 
    if (cur == null) 
    { 
     context.Actors.AddObject(entity); 
     return entity; 
    } 
    else 
    { 
     if (!entity.Mail.IsNullOrEmptyOrWhitespace() && cur.Mail != entity.Mail) 
      cur.Mail = entity.Mail; 
    //there are more of these... 

     return cur; 
    } 
} 

Je ne peux pas croire que cela est ainsi « le droit » de le faire . Il se sent et semble juste faux. Peut-être que EF est à blâmer aussi, prendre

FirstEntityType first = new FirstEntityType(); 
first.Id = 2; 
List<SecondType> list = CreateList(); //Let's say this returns a List with 10 elements 
context.FirstEntityType.AddObject(first); 

for (int i = 0; i < list.Count; i++) 
{ 
    list[i].First = first; 
} 

//just for arguments sake a second for 
for (int i = 0; i < list.Count; i++) 
{ 
    context.SecondType.AddObject(list); 
} 

context.SaveChanges(); 

Je ne l'ai pas testé ce morceau de code particulier, mais de ce que j'ai vécu est que je vais finir avec 10 nouvelles entrées pour SecondType et si je ne me trompe pas 11 pour FirstEntityType.

Pourquoi? Pourquoi n'y a-t-il pas un mécanisme dans EF qui dit "Hey, attendez une minute - ce sont les mêmes!" Est-ce que je me trompe en pensant que EF devrait se comporter comme si j'utilisais le db directement? Dans mon exemple, j'ai ajouté "premier" afin que je puisse supposer que chaque fois que j'utilise "premier", il est référencé. (J'espère vraiment que mon exemple fonctionne comme décrit - je n'ai ni le temps ni le désir de le tester)

+0

Non, vous n'obtiendrez pas 11 entrées pour FirstEntityType, juste une dans votre base de données. Tant que vous êtes dans un ObjectContext, les identités sont préservées lorsque vous ajoutez un objet au contexte. Mais lorsque vous exécutez ce code une seconde fois (dans un nouveau contexte), vous obtiendrez en effet un second FirstEntityType (ou une exception de dababase lorsque FirstEntityType.id est une clé primaire non auto-incrémentée). Donc: Entity Framework dit: "Ce sont les mêmes!", Mais pas grâce au même id-champ mais parce que AddObject a créé un EntityKey (temporaire) qui identifie l'objet de façon unique dans un ObjectContext. – Slauma

+0

Je voudrais avoir toujours ce code parce que je faisais quelque chose comme ça et a fini avec beaucoup d'entrées. Et puisque tout était joliment enveloppé dans un contexte {), je suis presque sûr d'avoir utilisé le même contexte. Peut-être que c'était quelque chose de différent qui a causé ce comportement ou j'ai foiré quelque part. J'étais vraiment frustré après un moment et je voulais que le travail soit terminé. Peut-être que je vais faire quelques tests si j'ai le temps. Et agréable de voir que quelqu'un a tout lu :) –

Questions connexes