Entity Framework 4 CTP 4 / CTP 5 Patrón de Repositorio Genérico y Unidad Comprobable
Estoy jugando con la última versión de Entity Framework CTP 5 y construyendo un sencillo asp.net MVC blog donde solo tengo dos tablas: Post y Comentarios. Esto se hace completamente en POCO, solo necesito ayuda en la parte DbContext, donde necesito que sea unit testable (usando IDbSet?) y necesito un patrón de repositorio simple / genérico para agregar, actualizar, eliminar, recuperar. Cualquier ayuda es apreciada.
Gracias.
3 answers
Comience con usted DbContext, cree un nuevo archivo llamado Base de datos.cs:
Base de datos.cs
public class Database : DbContext
{
private IDbSet<Post> _posts;
public IDbSet<Post> Posts {
get { return _posts ?? (_posts = DbSet<Post>()); }
}
public virtual IDbSet<T> DbSet<T>() where T : class {
return Set<T>();
}
public virtual void Commit() {
base.SaveChanges();
}
}
Defina una IDatabaseFactory e impleméntela con DatabaseFactory:
IDatabaseFactory.cs
public interface IDatabaseFactory : IDisposable
{
Database Get();
}
DatabaseFactory.cs
public class DatabaseFactory : Disposable, IDatabaseFactory {
private Database _database;
public Database Get() {
return _database ?? (_database = new Database());
}
protected override void DisposeCore() {
if (_database != null)
_database.Dispose();
}
}
Método de extensión desechable:
Desechable.cs
public class Disposable : IDisposable
{
private bool isDisposed;
~Disposable()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if(!isDisposed && disposing)
{
DisposeCore();
}
isDisposed = true;
}
protected virtual void DisposeCore()
{
}
}
Ahora podemos definir nuestro IRepository y nuestro RepositoryBase
IRepository.cs
public interface IRepository<T> where T : class
{
void Add(T entity);
void Delete(T entity);
void Update(T entity);
T GetById(long Id);
IEnumerable<T> All();
IEnumerable<T> AllReadOnly();
}
Base de repositorios.cs
public abstract class RepositoryBase<T> where T : class
{
private Database _database;
private readonly IDbSet<T> _dbset;
protected RepositoryBase(IDatabaseFactory databaseFactory)
{
DatabaseFactory = databaseFactory;
_dbset = Database.Set<T>();
}
protected IDatabaseFactory DatabaseFactory
{
get; private set;
}
protected Database Database
{
get { return _database ?? (_database = DatabaseFactory.Get()); }
}
public virtual void Add(T entity)
{
_dbset.Add(entity);
}
public virtual void Delete(T entity)
{
_dbset.Remove(entity);
}
public virtual void Update(T entity)
{
_database.Entry(entity).State = EntityState.Modified;
}
public virtual T GetById(long id)
{
return _dbset.Find(id);
}
public virtual IEnumerable<T> All()
{
return _dbset.ToList();
}
public virtual IEnumerable<T> AllReadOnly()
{
return _dbset.AsNoTracking().ToList();
}
}
Ahora puedes crear tu IPostRepository y PostRepository:
Yo postergaría.cs
public interface IPostRepository : IRepository<Post>
{
//Add custom methods here if needed
Post ByTitle(string title);
}
Postrepositorio.cs
public class PostRepository : RepositoryBase<Post>, IPostRepository
{
public PostRepository(IDatabaseFactory databaseFactory) : base(databaseFactory)
{
}
public Post ByTitle(string title) {
return base.Database.Posts.Single(x => x.Title == title);
}
}
Por último, el UoW:
Unidad de trabajo.cs
public interface IUnitOfWork
{
void Commit();
}
Unidad de trabajo.cs
private readonly IDatabaseFactory _databaseFactory;
private Database _database;
public UnitOfWork(IDatabaseFactory databaseFactory)
{
_databaseFactory = databaseFactory;
}
protected Database Database
{
get { return _database ?? (_database = _databaseFactory.Get()); }
}
public void Commit()
{
Database.Commit();
}
Usando en su controlador:
private readonly IPostRepository _postRepository;
private readonly IUnitOfWork_unitOfWork;
public PostController(IPostRepository postRepository, IUnitOfWork unitOfWork)
{
_postRepository = postRepository;
_unitOfWork = unitOfWork;
}
public ActionResult Add(Post post) {
_postRepository.Add(post);
_unitOfWork.Commit();
}
Usted tendrá que utilice un contenedor IoC como StructureMap para hacer que esto funcione. Puede instalar structure map a través de NuGet, o si está utilizando MVC 3, puede instalar el paquete StructureMap-MVC NuGet. (Enlaces Abajo)
Install-Package StructureMap.MVC4
Install-Package StructureMap.MVC3
Si tiene preguntas, hágamelo saber. Espero que ayude.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-10 18:58:13
Me encanta este artículo en profundidad sobre Entity Framework 4 POCO, Repositorio y Patrón de Especificación
Http://huyrua.wordpress.com/2010/07/13/entity-framework-4-poco-repository-and-specification-pattern/
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-26 11:10:47
Lo único que haría de manera diferente es en la implementación, es decir, exponer el IPostRepository en la capa de servicio y tener un campo de interfaz de tipo IPostService en el controlador como otra capa de abstracción, pero por lo demás este es un buen ejemplo, bueno, Paul.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-10 19:40:06