7

He encontrado lo que parece ser un problema común: estoy actualizando valores en mi base de datos, pero EF está utilizando su copia original en memoria del objeto y estos valores modificados no se reflejan en los datos mostrados. Entiendo por qué es esto, pero no puedo encontrar una manera de evitarlo.¿Cómo desactivo el seguimiento de cambios en el nivel de DbContext en EF 4.1 RC?

La solución más común parece ser MergeOptions.NoTracking para desactivar por completo el seguimiento de cambios (o usar el método de extensión AsNoTracking() al realizar consultas) y forzar una actualización cada vez que se accede al objeto, lo que está bien para mis propósitos.

Tengo un repositorio genérico base que mis otros repositorios heredan de:

public abstract class RepositoryBase<T> where T : class 
{ 
    private readonly IDbSet<T> _dbset; 
    private readonly IUnitOfWork _unitOfWork; 

    protected RepositoryBase(IUnitOfWork unitOfWork) 
    { 
     _unitOfWork = unitOfWork; 
     _dbset = _unitOfWork.Database.Set<T>(); 
    } 

    public virtual IQueryable<T> All() 
    { 
     return _dbset; 
    } 

    // Some other IQueryable methods here (Query, GetByProductCode etc) 

    public virtual T Get(long id) 
    { 
     return _dbset.Find(id); 
    } 
}  

Y un DbContext así:

public class Db : DbContext 
{ 
    private IDbSet<Product> _products; 

    public IDbSet<Product> Products 
    { 
     get { return _products ?? (_products = DbSet<Product>()); } 
    } 

    public virtual IDbSet<T> DbSet<T>() where T : class 
    { 
     return Set<T>(); 
    } 

    public virtual void Commit() 
    { 
     base.SaveChanges(); 
    } 
} 

Si cambio el método de mi repositorio All() así:

public virtual IQueryable<T> All() 
{ 
    return _dbset.AsNoTracking(); 
} 

obtengo el resultado deseado - una actualización en la base de datos se refleja cuando la página que muestra los productos se actualiza. Sin embargo, no puedo hacer esto en el método Get(), ya que ese método de extensión solo funciona en un IQueryable.

Idealmente me gustaría desactivar esta opción en el nivel DbContext ya que nunca necesitará cambiar de seguimiento, pero no parece ser una manera obvia de hacerlo, y no hay casi cero la documentación sobre el tema (a menos que alguien me pueda indicar algo? ¡Por favor!).

He intentado añadir un constructor para la DbContext con estas opciones de configuración desactivada:

public Db() 
{ 
    base.Configuration.ProxyCreationEnabled = false; 
    base.Configuration.AutoDetectChangesEnabled = false; 
} 

pero tengo que admitir que sólo supongo que lo que realmente hacen (que sólo los encontré a través de mirar en la fuente código), y no parecen tener ningún efecto de todos modos.

Cualquier ayuda sería muy apreciada. Si más información/código ayudaría, házmelo saber.

Respuesta

6

Si desea forzar el contexto para obtener datos nuevos cada vez que no desee utilizar el método Find. Find método siempre consulta primero el almacenamiento interno. Use esto en su lugar:

public virtual T Get(long id) 
{ 
    return All().SingleOrDefault(e => e.Id == id); 
} 

Pero no entiendo, ¿qué necesita esto? ¿Qué quiere decir por:

una actualización en la base de datos se refleja cuando la página donde se presentan los productos se actualiza

El contexto es unidad de trabajo. Se debe usar como unidad de trabajo: en aplicaciones web o servicios web significa crear una nueva instancia de contexto por solicitud. En la aplicación winforms/wpf significa usar el contexto por bloque lógico (por presentador, etc.). Por eso deberías necesitar esto solo en escenarios muy específicos pero lo quieres a nivel mundial. Parece que su descripción está reutilizando el contexto entre las solicitudes, que es completely bad solution. No hay costos de rendimiento en el contexto de recreación para cada solicitud.

+0

Gracias por la respuesta. Pensé que * estaba * creando un nuevo contexto por solicitud, pero debido a lo que has señalado aquí, sospecho que podría tener algo mal configurado en la configuración de mi Ninject ... ¡Lo revisaré mañana y volveré a informar! –

+0

Parece que este es el problema. No estoy creando un nuevo DbContext por solicitud, o más bien, Ninject no lo es, aunque he especificado 'InRequestScope()' en la inyección. Creo que ahora es una pregunta aparte, pero gracias por su ayuda para llegar tan lejos. –

+0

He aceptado esta respuesta a pesar de que * no * responde * directamente a la pregunta, porque me llevó a una solución. –

Cuestiones relacionadas