2011-01-27 6 views
11

Me preguntaba cómo enfoca tus Dbcontexts en Entity Framework para que no uses un solo Dbcontext para toda tu aplicación. Soy nuevo en Entity Framework y he estado leyendo tutoriales, pero todos usaron un solo Dbcontext como ejemplo, por lo que EF es prácticamente una caja negra para mí en este momento.Cómo delimitar Dbcontexts (para evitar el contexto de singleton para toda la aplicación)

Digamos, por ejemplo, tengo 3 modelos:

  • Pon
  • usuario
  • comentario

Cada modelo está relacionado entre sí (D Enviar pertenece al usuario, comentario pertenece al usuario y a la publicación). ¿Hago un Dbcontext para cada uno individualmente? Pero eso no sería correcto ya que todos están relacionados, ¿o podría hacer un Dbcontext para cada escenario que necesito? Por ejemplo, si solo necesito consultar Publicaciones y Comentarios y no usuario, eso sería un PostCommentsContext. Y luego tendríamos un PostUserCommentContext ...

+1

Además, cuando utiliza UnitOfWork con un ORM, debe tener en cuenta que si falla una confirmación, entonces necesita un nuevo Contexto/Unidad de Trabajo http://lavinski.tumblr.com/post/9114111237/object-relational-mapper -exceptions –

Respuesta

7

La mejor solución sería utilizar una unidad de trabajo para ajustar el contexto de datos, así como administrar la vida útil de la conexión y permitirle trabajar con múltiples repositorios (si estaba dispuesto a seguir ese camino) .

Resumen de la ejecución:

  • crear una interfaz (IUnitOfWork) que expone las propiedades de sus DbSet 's, así como un método llamado Commit
  • Crear una aplicación (EntityFrameworkUnitOfWork), implementando según sea necesario. Commit simplemente llama a SaveChanges en la clase base (DbContext), y también proporciona un buen enganche para la lógica de último minuto.
  • Su controlador acepta una IUnitOfWork, utilizar DI (preferentemente) para resolver una EntityFrameworkUnitOfWork, con un HTTP-marco con ámbito vida entorno (StructureMap es bueno para esto)
  • (opcional, pero recomendado) crear un repositorio que también toma el IUnitOfWork, y funciona a través de su controlador.

HTH

EDITAR - En respuesta a los comentarios

Oh, ¿cómo se puede hacer un trabajo que implica la creación de registros en varios modelos, entonces? es decir, crear un nuevo usuario y una nueva publicación en la misma transacción.

Dado que usa ASP.NET MVC, los controladores deben aceptar un IUnitOfWork en su constructor.

He aquí un ejemplo, basado en lo que has pedido

public SomeController : Controller 
{ 
    private IUnitOfWork _unitOfWork; 
    private IUserRepo _userRepo; 
    private IPostRepo _postRepo; 

    public SomeController(IUnitOfWork unitOfWork, IUserRepo userRepo, IPostRepo postRepo) 
    { 
     _unitOfWork = unitOfWork; // use DI to resolve EntityFrameworkUnitOfWork 
     _userRepo = userRepo; 
     _postRepo = postRepo; 
    } 

    [HttpPost] 
    public ActionResult CreateUserAndPost(User user, Post post) 
    { 
     // at this stage, a HTTP request has come in, been resolved to be this Controller 
     // your DI container would then see this Controller needs a IUnitOfWork, as well 
     // as two Repositories. DI smarts will resolve each dependency. 
     // The end result is a single DataContext (wrapped by UoW) shared by all Repos. 
     try 
     { 
     userRepo.Add(user); 
     postRepo.Add(post); 
     // nothing has been sent to DB yet, only two objects in EF graph set to EntityState.Added 
     _unitOfWork.Commit(); // two INSERT's pushed to DB 
     } 
     catch (Exception exc) 
     { 
      ModelState.AddError("UhOh", exc.ToString()); 
     } 
    } 
} 

Y una última pregunta, ¿qué hacer con ámbito curso de la vida del HTTP-contexto?

objetos en DI-talk tienen configuración de administración de alcance que incluyen por hilo, por sesión, por la petición http, Singleton, etc.

HTTP-marco con ámbito es el ajuste recomendado para aplicaciones web. Significa "actualizar un contexto cuando aparece una solicitud HTTP y deshacerse de él cuando finaliza la solicitud".

+0

Actualmente estoy usando el patrón de repositorio. Sin embargo, con el patrón de unidad de trabajo, ¿no deberían los repositorios estar en la UoW? ¿Qué sucede si está trabajando en varios modelos (por lo tanto, varios repositorios) – Alex

+0

@Alex? Podría hacerlo, sí, pero mi preferencia es mantenerlos separados, y los Repositorios deberían tomar una unidad de trabajo en su ctor, que era creado de antemano (por un contenedor DI, cuando entra una solicitud HTTP). ¿Ya tu sabes? – RPM1984

+0

¿Cómo puede hacer un trabajo que implique crear registros en varios modelos, entonces? es decir, crear un nuevo usuario y una nueva publicación en la misma transacción. Y una pregunta más, ¿qué hace la vida útil del contexto HTTP? ¡Gracias! – Alex

6

Use 1 DbContext! Eso te hará la vida más fácil. No se preocupe por el rendimiento, los datos que no son necesarios o consultados no se cargarán y no consumirán ningún recurso.

public class UserContext : DbContext 
{ 
    public DbSet<User> Users { get; set; } 
    public DbSet<Post> Posts { get; set; } 
    public DbSet<Comment> Comments { get; set; } 
} 

Para algunos escenarios, es posible que desee 2 o más contextos.

Un contexto como el anterior para contener todos los datos de entrada necesarios para que funcione su aplicación y otro contexto para, por ejemplo, almacenar informes generados a partir de esos datos de front-end, y que solo se utiliza en el back-end de tu aplicación.

+1

Upvoted por ser la única respuesta que no sugiere envolver 'DbContext' con algunos' IUnitOfWork' :) –

0

estoy experimentando con UnitOfWork, aquí es lo que he llegado con ...

Primero creado un IUnitofWork que sólo contiene un método. Commit();

Entonces mi dbContext tiene este aspecto

public class myContext : DbContext, IUnitOfWork 
{ 
    public DbSet<Users> Users { get; set; } 
    public DbSet<Addresses> Address { get; set; } 

    public void Save() 
    { 
     SaveChanges(); 
    } 
} 

Mis clases toman un repositorio UnitOfWork en sus ctors.

public class UserRepository : IRepository<Position>  
{ 
    private myContext _context; 

    public UserRepository (IUnitOfWork unitOfWork) 
    { 
     if (unitOfWork == null) 
      throw new ArgumentNullException("unitOfWork"); 

     _context = unitOfWork as myContext; 
    } 
    /// other methods /// 
} 

continuación, el código en el controlador sería algo como esto

_unitOfWork = new myContext(); 
_userDB = new UserRepository(_unitOfWork); 
_addressDB = new AddressRepository(_unitOfWork); 
_userDB.Add(newUser); 
_addresesDB.Add(newAddress); 
_unitOfWork.Save(); 

He depurado y ha demostrado que no hay datos está comprometida hasta que se llame al método Save de la _unitOfWork. Cosas muy interesantes!

Cuestiones relacionadas