2010-06-25 4 views
6

Entity Framework 4 - STE - DB simple avec blogs à table unique ayant colonne blogid PK ...Entity Framework ObjectContext implémentation correcte de Unit Of Work Pattern?

var samplesDbEntities = new SamplesDBEntities(); 
var blogId = Guid.NewGuid(); 
samplesDbEntities.Blogs.AddObject(new Blog() { BlogID = blogId }); 
var objectSetResult = samplesDbEntities.Blogs 
             .Where(p => p.BlogID == blogId) 
             .SingleOrDefault(); 

(résultat de l'exécution de code => == null objectSetResult après la dernière ligne)

AFAIK, ObjectContext est l'implémentation du pattern UoW et dans ce cas je suppose que je devrais récupérer le résultat de ObjectSet (Repository) juste "marqué comme transitoire" Quelqu'un peut-il m'expliquer ce que je fais mal et pourquoi objectSetResult a une valeur nulle ici ?

(Oui, je suis au courant de ObjectStateManager, mais pour moi, il est plus d'un patch pour le problème architectural haut mentionné)

Répondre

1

Le motif violé dans votre exemple n'est pas un motif d'unité de travail, mais un mappage d'identité.

Unité de travail suivez les modifications apportées aux objets par votre code au lieu de vous en occuper manuellement.

Le modèle de mappage d'identité met en place un contexte d'objet pour avoir une instance d'entité unique pour une seule valeur de clé primaire.

Il est étrange pour moi mais Entity Framework (ainsi que LINQ 2 SQL) ne mappe pas l'identité de l'objet dans toutes les situations, et la situation décrite ci-dessus est l'un de ces cas.

4

Vous devez appeler

samplesDbEntities.SaveChanges(); 

avant requerying pour l'objet.

var samplesDbEntities = new SamplesDBEntities(); 
var blogId = Guid.NewGuid(); 
samplesDbEntities.Blogs.AddObject(new Blog() { BlogID = blogId }); 

samplesDbEntities.SaveChanges(); 

var objectSetResult = samplesDbEntities.Blogs 
            .Where(p => p.BlogID == blogId) 
            .SingleOrDefault(); 

Mise à jour

La raison pour laquelle vous ne recevez pas l'arrière utilisateur ajouté à objectSetResult est que d'appeler la méthode SingleOrDefault d'un objet résulte IQueryable dans une requête de base de données (une chaîne réelle de requête SQL est générée accoding à la condition "where", etc.), et puisque l'objet n'est pas (encore) dans la base de données, il ne sera pas retourné. Le nouvel objet est cependant attaché au contexte et EntityState est défini sur "Ajouté". Selon MSDN, les objets dans l'état Ajouté n'ont pas de valeurs d'origine dans ObjectStateEntry. L'état des objets dans un contexte d'objet est géré par ObjectStateManager. Donc, si vous voulez vérifier que l'objet a vraiment été attaché, vous pouvez chercher en appelant GetObjectStateEntry:

var samplesDbEntities = new SamplesDBEntities(); 
Blog blog = new Blog() { BlogID = Guid.NewGuid() }; 
samplesDbEntities.Blogs.AddObject("Blogs", blog); 

Blog addedBlog = (Blog)context.ObjectStateManager.GetObjectStateEntry(blog).Entity; 

Notez également que le EntityState de l'objet récupéré est « Ajouté ». Pour résumer - en ce qui concerne votre question initiale de savoir si c'est une implémentation correcte de UnitOfWork, je ne vois pas pourquoi pas. Il maintient en effet une liste d'objets et suit les changements, etc., etc. Le problème que vous avez rencontré, cependant, est lié au fait que vous récupérez des données du fournisseur sous-jacent, plutôt qu'à partir de la liste des objets actuellement attachés au le contexte.

+0

-1 cos cela ne répond pas à la question "Est-ce que Entity Framework ObjectContext est correctement implémenté de Unit Of Work Pattern?" – Restuta

+0

Assez juste. Voir la mise à jour – Yakimych

+2

Mon cas d'utilisation est qu'une entité est ajoutée et récupérée avant que la persistance ne se produise - quel est le but de UoW si je dois persister chaque entité seule et non en batch? En ce qui concerne le code de mise à jour, ne pensez-vous pas que le fait de savoir que j'ai besoin d'utiliser ObjectStateManager est mauvais (fuite d'infrastructure)? Pas le cas dans mon exemple trivial, mais que "get" peut se produire dans un endroit complètement différent où je ne saurais pas si quelque chose est ajouté. Pourquoi cela ne sera pas encapsulé à l'intérieur de l'OBjectSet lui-même (comme UoW devrait le faire) et juste être reconnu pendant la persistance? –

0

Merci de préciser votre point. J'ajoute ceci comme une autre réponse, car il y a pas mal de choses à dire à ce sujet. Comme je l'ai déjà dit, il n'y a pas de définition universelle stricte de l'état de la technique, de sorte que le sujet fait l'objet d'un débat bien sûr. Mes points sont les suivants:

  1. Vous ajoutez une entité au contexte, mais essayez de la récupérer à partir de la base de données. Conclure que ObjectContext n'est pas une implémentation correcte de UoW n'est pas logique.

  2. Si vous ajoutez des entités au contexte afin de les sortir plus tard pour une raison quelconque avant de modifier la base de données, vous n'utilisez pas EF comme il est destiné à être utilisé.En général, vous ne devriez pas utiliser ObjectStateManager pour le faire, mais vous pouvez:

    Blog addedBlog = context. 
         ObjectStateManager. 
         GetObjectStateEntries(EntityState.Added). 
         Where(ent => (ent.Entity is Blog) && ((Blog)ent.Entity).BlogID == blogID). 
         Select(ent => ent.Entity as Blog). 
         SingleOrDefault(); 
    
  3. Une unité de travail est un objet de contexte qui maintient des listes d'entités commerciales, suit les modifications apportées à leur état au cours d'une transaction commerciale. EF ObjectContext fait-il cela? Oui. Est-ce qu'il fournit une syntaxe raisonnable pour récupérer un objet qui est dans l'état "Ajouté"? Non, mais ce n'est pas une exigence pour une mise en œuvre «correcte» de toute façon. N'oubliez pas - EF est un ORM, et l'objectif est de suivre les modifications de votre base de données dans le code, et non les changements entre les différentes parties de votre code (c'est ce que vous avez pour votre logique métier).

Et en ce qui concerne: « quel est le point de UOW si je dois persister toutes les entités sur son propre et non dans le lot » - le point est que vous pouvez ajouter un tas d'objets au contexte, et persistez tout d'un coup en appelant SaveChanges. Comme je l'ai déjà mentionné, le contexte n'est pas destiné à être utilisé pour «transporter» vos objets d'affaires. Vous pouvez cependant les récupérer depuis ObjectStateManager sans conserver les modifications apportées à la base de données si vous le souhaitez.

+0

Vous avez dit "le point est que vous pouvez ajouter un tas d'objets au contexte, puis les conserver en une seule fois en appelant SaveChanges" Je suis d'accord avec ce 100% (c'est ce que j'ai dit). La manière décrite EF4 fonctionne, je peux ajouter 2x Post avec le même ID de différentes parties de mon code - tout va bien jusqu'à la persistance - quand la violation de PK se produirait. Je n'ai pas besoin de plus d'explications sur le fonctionnement d'EF4 * - Je le sais et je pense (architecturellement) qu'il est défectueux. On dirait que la question SO n'est pas un bon moyen d'avoir ces discussions alors j'écrirais un post de blog en fournissant plus de détails à ce sujet ... –

+0

J'ai voté pour que la question soit classée comme trop subjective mais j'ai besoin de 4 autres voix afin d'être fermé :) –

Questions connexes