2010-06-25 12 views
6

Entity Framework 4 - STE - DB sencillo con una sola mesa blogs que tienen la columna blogid PK ...¿La aplicación ObjectContext de Entity Framework es correcta para el patrón de unidad de trabajo?

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(); 

(resultado de la ejecución de código => objectSetResult == null después de la última línea)

AFAIK, ObjectContext es la implementación del patrón UoW y en cuyo caso creo que debería obtener el resultado de ObjectSet (Repository) simplemente "marcado como transitorio" ¿Puede alguien explicarme qué estoy haciendo mal y por qué objectSetResult tiene un valor nulo aquí ?

(Sí, soy consciente de ObjectStateManager, pero para mí es más de un parche para el problema arquitectónico mencionado superior)

Respuesta

1

El patrón violado en su ejemplo no es el patrón de unidad de trabajo, sino el mapeo de identidad.

La Unidad de trabajo realiza un seguimiento de los cambios realizados en los objetos por su código en lugar de hacerlo manualmente.

El patrón de asignación de identidad establece el contexto del objeto para tener una única instancia de entidad para el valor único de la clave principal.

Es extraño para mí, pero Entity Framework (así como también LINQ 2 SQL) no correlaciona la identidad del objeto en cada situación, y la situación descrita anteriormente es uno de esos casos.

4

Es necesario llamar

samplesDbEntities.SaveChanges(); 

antes de volver a consultar para el objeto.

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(); 

actualización

La razón por la que no está recibiendo el usuario vuelve a añadir en objectSetResult es que se genera una llamada al método SingleOrDefault de IQueryable resultados de objetos en una consulta de base de datos (una cadena de consulta SQL real teniendo en cuenta la condición de "dónde", etc.), y dado que el objeto no está (todavía) en la base de datos, no se devuelve. Sin embargo, el nuevo objeto está adjunto al contexto y su EntityState está configurado como "Agregado". Según MSDN, los objetos en el estado Agregado no tienen valores originales en ObjectStateEntry. El estado de los objetos dentro de un contexto de objeto es administrado por ObjectStateManager. Así que si usted quiere comprobar que el objeto realmente se ha unido, se puede recuperar llamando 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; 

También tenga en cuenta que el EntityState del objeto recuperado es "Agregado".

En resumen: con respecto a su pregunta inicial sobre si se trata de una implementación correcta de UnitOfWork, no veo por qué no. De hecho, mantiene una lista de objetos y rastrea los cambios, etc., etc. Sin embargo, el problema que encontraste está relacionado con el hecho de que estás obteniendo datos del proveedor subyacente, más bien de la lista de objetos actualmente conectados al contexto.

+0

-1 porque esto no responde a la pregunta exacta "¿Es la implementación correcta de Entity Framework ObjectContext de Unit Of Work Pattern?" – Restuta

+0

Bastante justo. Ver respuesta actualizada. – Yakimych

+2

Mi caso de uso es que una entidad se agrega y se recupera antes de que ocurra la persistencia: ¿cuál es el sentido de UoW si tengo que persistir cada entidad por sí misma y no en un lote? En cuanto al código de actualización, ¿no cree que el hecho de que tengo que saber que necesito usar ObjectStateManager es malo (una infraestructura con fugas)? No es el caso en mi muestra trivial, pero ese "obtener" puede ocurrir en un lugar completamente diferente donde no sabría si se agrega algo. ¿Por qué eso no se encapsulará en el propio OBjectSet (como debería hacerlo UoW) y solo se reconocerá durante la persistencia? –

0

Gracias por aclarar su punto. Estoy agregando esto como otra respuesta ya que hay mucho que decir al respecto.

AFAIK, no existe una definición universal estricta de UoW, por lo que el tema es objeto de debate, por supuesto. Mis puntos son los siguientes:

  1. Está agregando una entidad al contexto, pero tratando de recuperarlo de la base de datos. Concluir que ObjectContext no es una implementación correcta de UoW no es lógico.

  2. Si está agregando entidades al contexto para luego sacarlas por alguna razón antes de que persistan los cambios en la base de datos, no está utilizando EF como debe ser utilizado.En general, usted no debe usar ObjectStateManager de hacer eso, pero puede hacerlo:

    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. Una unidad de trabajo es un objeto de contexto que mantiene una lista de entidades empresariales, realiza un seguimiento de los cambios a su estado durante una transacción de negocios. ¿EF ObjectContext hace eso? Sí. ¿Proporciona una sintaxis razonable para recuperar un objeto que está en el estado "Agregado"? No, pero eso no es un requisito para una implementación de UoW "correcta". No lo olvides: EF es un ORM, y el objetivo es rastrear los cambios a tu base de datos en el código, y no los cambios entre las diferentes partes de tu código (para eso tienes tu lógica de negocio).

Y respecto: "¿cuál es el punto de UoW si tengo que persisten toda entidad por sí misma y no en lotes" - el punto es que se puede añadir un montón de objetos con el contexto, y luego persistir a todos de una vez llamando a SaveChanges. Como ya mencioné, el contexto no está destinado a ser usado para "transportar" sus objetos comerciales. Sin embargo, puede recuperarlos de ObjectStateManager sin cambios persistentes en el DB si lo desea.

+0

Usted dijo "el punto es que puede agregar un montón de objetos al contexto y luego persistirlos de una vez al llamar a SaveChanges" Estoy de acuerdo con ese 100% (eso es lo que dije). La forma descrita en que EF4 funciona Puedo agregar 2 publicaciones con la misma ID de diferentes partes de mi código, todo bien hasta la persistencia, cuando ocurra la violación de PK. No necesito más explicaciones sobre cómo funciona EF4 * * - Lo sé y creo que (arquitectónicamente) tiene fallas. Parece que la pregunta SO no es un buen medio para tener estas discusiones, así que escribiría una publicación en el blog proporcionando más detalles sobre esto ... –

+0

He votado a favor de que la pregunta se haya cerrado como "demasiado subjetiva" pero necesito 4 voces más para estar cerrado :) –

Cuestiones relacionadas