Question

J'utilise le "technique de talon" à mettre à jour Mes POCO (utilisés dans un contexte détaché, ASP.NET MVC).

Ceci est le code que j'ai actuellement dans mon contrôleur (qui fonctionne):

[HttpPost]
public ActionResult Edit(Review review)
{
   Review originalReview = _userContentService.FindById(review.PostId) as Review;
   var ctx = _unitOfWork as MySqlServerObjectContext;
   ctx.ApplyCurrentValues("MyEntities.Posts", review);
   _unitOfWork.Commit();
   // ..snip - MVC stuff..
}

Comme vous pouvez le voir, il y a une odeur de code partout. :)

Quelques points:

  1. J'utilise l'injection de dépendance (basée sur l'interface) pour pratiquement tout
  2. J'utilise l'unité de modèle de travail pour abstraction objetContext et donne de la persistance sur plusieurs référentiels
  3. Actuellement mon Initofwork L'interface n'a qu'une méthode: void Commit();
  4. Le contrôleur a IUserContentService et IUnitOfWork injecter par di
  5. IUserContentService appels Find dans les référentiels, qui utilisent le ObjectContext.

Ce sont deux choses que je n'aime pas avec mon code ci-dessus:

  1. Je ne veux pas lancer le Initofwork comme MySqlServerObjectContext.
  2. Je ne veux pas que le contrôleur ait à se soucier ApplyCurrentValues

Je veux essentiellement que mon code ressemble à ceci:

[HttpPost]
public ActionResult Edit(Review review)
{
   _userContentService.Update(review);
   _unitOfWork.Commit();
   // ..snip - MVC stuff..
}

Des idées comment puis-je faire cela? (ou quelque chose de similaire).

J'ai déjà l'intelligence pour déterminer le nom de l'ensemble des entités en fonction du type (combinaison de génériques, de la pluralisation), alors ne vous inquiétez pas trop à ce sujet.

Mais Je me demande où le meilleur endroit pour mettre ApplyCurrentValues est? Il ne semble pas approprié de le mettre dans le IUnitOfWork Interface, comme il s'agit d'une préoccupation de persistance (EF). Pour la même raison, il n'appartient pas au service. Si je le mets dans mon MySqlServerObjectContext classe (a du sens), d'où devrais-je l'appeler, car rien n'a directement accès à cette classe - il est injecté via DI quand quelque chose demande IUnitOfWork.

Des pensées?

ÉDITER

J'ai une solution ci-dessous en utilisant la technique du stub, mais le problème est que si j'avais récupéré l'entité que je mets à jour au préalable, il lance une exception, indiquant une entité avec cette clé.

Ce qui a du sens, même si je ne sais pas comment résoudre ce problème?

Dois-je "vérifier si l'entité est déjà jointe, sinon, attachez-la?"

Des experts EF4 peuvent-ils aider?

ÉDITER

NeverMind - Found la solution, voir la réponse ci-dessous.

Était-ce utile?

La solution

Je l'ai compris - ce n'était pas facile, donc je vais essayer d'expliquer le mieux que je peux. (pour ceux qui se soucient)

Code pertinent du contrôleur:

// _userContentService is IUserContentService
_userContentService.Update(review);

Donc, mon contrôleur appelle une méthode appelée Update sur IUserContentService, passant par le fortement typique Review objet.

Service de contenu utilisateur Code pertinent

public void Update(Post post)
{
   // _userContentRepository is IPostRepository
   _userContentRepository.UpdateModel(post);
}

Donc, mon service appelle une méthode appelée UpdateModel sur IPostRepository, passant par le fortement typique Review objet.

Maintenant, voici la partie délicate.

J'ai vraiment Pas de référentiels spécifiques. j'ai un référentiel générique appelé GenericRepository<T> : IRepository<T>, qui gère Tous les différents référentiels.

Alors quand quelque chose demande un IPostRepository (ce que faisait mon service), Di lui donnerait un GenericRepository<Post>.

Mais maintenant, je lui donne un PostRepository:

public class PostRepository : GenericRepository<Post>, IPostRepository
{
   public void UpdateModel(Post post)
   {
      var originalPost = CurrentEntitySet.SingleOrDefault(p => p.PostId == post.PostId);
      Context.ApplyCurrentValues(GetEntityName<Post>(), post);
   }
}

Et parce que la classe dérive de Générique, il hérite de toute la logique du référentiel de base (trouver, ajouter, etc.).

Au début, j'ai essayé de mettre ça UpdateModel code dans le Générique classe elle-même (et alors je n'aurais pas eu besoin de ce référentiel spécifique), mais le problème est que la logique pour récupérer l'entité existante est basée sur une clé d'entité spécifique, dont la GenericRepository<T> ne le saurait pas.

Mais le résultat final est le piqûre est caché au fond des profondeurs de la couche de données, et je me retrouve avec un contrôleur vraiment propre.

ÉDITER

Cette "technique de stub" fonctionne également:

public void UpdateModel(Post post)
{
   var stub = new Review {PostId = post.PostId};
   CurrentEntitySet.Attach(stub);
   Context.ApplyCurrentValues(GetEntityName<Post>(), post);
}

Mais le problème est parce que Poste est abstrait, je ne peux pas instancier et je devrais donc vérifier le type de message et créer des talons pour Chacun type dérivé. Pas vraiment une option.

Edit 2 (la dernière fois)

D'accord, la "technique du stub" fonctionne avec les cours abstraits, alors maintenant le problème de concurrence est résolu.

J'ai ajouté un paramètre de type générique à mon UpdateModel Méthode, et le spécial nouvelle () contrainte.

Mise en œuvre:

public void UpdateModel<T>(T post) where T : Post, new()
{
   var stub = new T { PostId = post.PostId };
   CurrentEntitySet.Attach(stub);
   Context.ApplyCurrentValues(GetEntityName<Post>, post);
}

Interface:

void UpdateModel<T>(T post) where T : Post, new();

Cela m'empêche de devoir comprendre le type de T manuellement, empêche les problèmes de concurrence et empêche également un voyage supplémentaire à la base de données.

Jolie groovy.

Edit 3 (je pensais que la dernière fois était la dernière fois)

La "technique du stub" ci-dessus fonctionne, mais si je récupére l'objet à l'avance, il lance une exception indiquant une entité avec cette clé existe déjà dans l'OSM.

Quelqu'un peut-il conseiller comment gérer cela?

Edit 4 (OK - c'est ça!)

J'ai trouvé la solution, grâce à cette réponse, alors répondez: Est possible de vérifier si un objet est déjà attaché à un contexte de données dans Entity Framework?

J'avais essayé de "vérifier si l'entité est jointe" en utilisant le code suivant:

ObjectStateEntry entry;
CurrentContext.ObjectStateManager.TryGetObjectStateEntry(entity, out entry);

Mais il est toujours revenu nul, même grâce à mon exploré l'OSM, je pouvais y voir mon entité avec la même clé.

Mais ce code fonctionne:

CurrentContext.ObjectStateManager.TryGetObjectStateEntry(CurrentContext.CreateEntityKey(CurrentContext.GetEntityName<T>(), entity), out entry)

Peut-être que parce que j'utilise PUCO POCO, l'OSM a eu du mal à comprendre la clé d'entité, qui sait.

Oh et une autre chose que j'ai ajoutée - afin que je n'ai pas à ajouter de référentiel spécifique pour chaque entité, j'ai créé un attribut appelé "EntityKey"(Attribut de propriété publique).

Tous les POCO doivent avoir 1 propriété publique décorée de cet attribut, ou je lance une exception dans mon module de référentiel.

Ainsi, mon référentiel générique recherche ensuite cette propriété afin de créer / configurer le talon.

Oui - il utilise la réflexion, mais c'est une réflexion intelligente (basée sur des attributs) et j'utilise déjà la réflexion pour la plularisation des noms d'ensemble de T.

Quoi qu'il en soit, un problème résolu - tout fonctionne bien maintenant!

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top