Usuário com melhor resposta
Entity Framework + UnitOfWork

Pergunta
-
Boa tarde,
Estou com uma duvida ao usar UnitOfWork com EF.
Com os exemplos que encontrei, eu crio uma classe static, com uma propriedade static(contexto), e utilizo nas classes de repositório.
A dúvida é, como o objeto a classe e o objeto são estáticos, será compartilhado por todos os usuários.
Existe uma maneira melhor de usar UnitOfWork ( De preferencia não usando repositório genérico).
Uso a versão 4.4 do EF.
Desde já, obrigado!
Respostas
-
Sim, concerteza ... na verdade é o mesmo contexto mas, instância diferentes, mas, existe uma forma de contornar isso amigo!
Assim!
Coloque um Construtor com Parametro passando o seu Contexto nesse Construtor!
Exemplo!
public class Repository<T>: IRepository<T> where T: class, new() { public System.Data.Entity.DbContext Context { get; private set; } public Repository() { this.Context = Activator.CreateInstance<DatabasePhoneEntities>(); this.Model = this.Context.Set<T>(); } public Repository(DbContext Context) { this.Context = Context; this.Model = this.Context.Set<T>(); } }
Ai na codificação se no caso for utilizar Entidades que elas precisam trabalhar no mesmo contexto
ficaria assim:
DatabasePhoneEntities DbMaster = new DatabasePhoneEntities(); Repository<Notice> Db = new RepositoryNotice(DbMaster); Repository<Credit> DbCredit = new RepositoryCredit(DbMaster);
Ou seja a mesma instância do contexto é repassada nos repositorios, não trazendo o erros que você já relatou !!!
OK!
Faça os testes funciona perfeitamente!
- Sugerido como Resposta Fulvio Cezar Canducci Dias terça-feira, 3 de dezembro de 2013 12:51
- Marcado como Resposta Alexsander Rodrigues terça-feira, 3 de dezembro de 2013 13:19
Todas as Respostas
-
Eu não indicaria mesmo utilizar Static, pode criar uma grande sobrecarga no seu projeto e pode ser até prejudicial pelo fato que você mesmo relatou!
A melhor maneira é utilizando Repositório Generico ... !!!
Se pode criar e ficar repetindo todo as vezes seu código por isso utilizamos repositorio generico que a pela tipagem fica melhor de se trabalhar mas, ai é de você
pode criar uma Interface e gerar para cada Entidade sua unidade de trabalho ... !!! mas, vai ter que ficar reescrevendo coisas que no repositorio generico seria muito mais simples e melhor uma vez só!
- Editado Fulvio Cezar Canducci Dias segunda-feira, 2 de dezembro de 2013 23:45
-
Mas mesmo que eu faça isso, ainda terei problema, já que será um contexto por repositório.
Já que lido com objetos complexos, ainda terei o problema de objeto modificado em outro contexto.
Não queria usar repositório genérico, porque já tenho a implementação.
-
Mas mesmo que eu faça isso, ainda terei problema, já que será um contexto por repositório.
Já que lido com objetos complexos, ainda terei o problema de objeto modificado em outro contexto.
Não queria usar repositório genérico, porque já tenho a implementação.
Vamos lá!
Eu lido com objeto Complexos (Cite ????)
Você não é obrigado a usar Genérico mas, imagine criar um interface e gerar todos os unitofwork de cada entidade ??? vai causar repetição de código e na POO isso não é aceitavel !!! entendeu ?
-
Concordo que não é viável fazer isso.
O problema que eu tinha era que, quando cada repositório tem seu contexto, quando ia fazer updates, gerava problema.
Exemplo, eu tenho um objeto A, que tem como propriedade um objeto B.
Como os objetos são carregados em diferentes contextos, ao persistir mudança em A, da erro.
-
Sim, concerteza ... na verdade é o mesmo contexto mas, instância diferentes, mas, existe uma forma de contornar isso amigo!
Assim!
Coloque um Construtor com Parametro passando o seu Contexto nesse Construtor!
Exemplo!
public class Repository<T>: IRepository<T> where T: class, new() { public System.Data.Entity.DbContext Context { get; private set; } public Repository() { this.Context = Activator.CreateInstance<DatabasePhoneEntities>(); this.Model = this.Context.Set<T>(); } public Repository(DbContext Context) { this.Context = Context; this.Model = this.Context.Set<T>(); } }
Ai na codificação se no caso for utilizar Entidades que elas precisam trabalhar no mesmo contexto
ficaria assim:
DatabasePhoneEntities DbMaster = new DatabasePhoneEntities(); Repository<Notice> Db = new RepositoryNotice(DbMaster); Repository<Credit> DbCredit = new RepositoryCredit(DbMaster);
Ou seja a mesma instância do contexto é repassada nos repositorios, não trazendo o erros que você já relatou !!!
OK!
Faça os testes funciona perfeitamente!
- Sugerido como Resposta Fulvio Cezar Canducci Dias terça-feira, 3 de dezembro de 2013 12:51
- Marcado como Resposta Alexsander Rodrigues terça-feira, 3 de dezembro de 2013 13:19
-
Uso do UnitOfWork com Generic é bem simples e muito prático.
Interface IUnitOfWork
namespace Exemplo.Repository { public interface IUnitOfWork : IDisposable { GenericRepository<Estado> EstadosRepository { get; } GenericRepository<Cidade> CidadesRepository { get; } BannersRepository BannersRepository { get; } void Save(); } }
ExemploUnitOfWork implementando a interface
namespace Exemplo.Repository { public class ExemploUnitOfWork : IUnitOfWork { public ExemploUnitOfWork() { _disposed = false; _context = new ExemploContext(); } #region Private private bool _disposed; private readonly ExemploContext _context; private GenericRepository<Estado> _estadosRepository; private GenericRepository<Cidade> _cidadesRepository; private BannersRepository _bannersRepository; public GenericRepository<Estado> EstadosRepository { get { return _estadosRepository ?? (_estadosRepository = new GenericRepository<Estado>(_context)); } } public GenericRepository<Cidade> CidadesRepository { get { return _cidadesRepository ?? (_cidadesRepository = new GenericRepository<Cidade>(_context)); } } public BannersRepository BannersRepository { get { return _bannersRepository ?? (_bannersRepository = new BannersRepository(_context)); } } public void Save() { _context.SaveChanges(); } protected virtual void Dispose(bool disposing) { if (!_disposed) { if (disposing) { _context.Dispose(); } } _disposed = true; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } } }
Repositório Generico (Get, Delete, Update, Etc)
namespace Exemplo.Repository { public class GenericRepository<TEntity> : IDisposable where TEntity : class { private bool disposed = false; internal DbContext context; internal DbSet<TEntity> dbSet; public GenericRepository(DbContext context) { this.context = context; this.dbSet = context.Set<TEntity>(); } public virtual IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "") { IQueryable<TEntity> query = dbSet; if (filter != null) { query = query.Where(filter); } foreach (var includeProperty in includeProperties.Split (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) { query = query.Include(includeProperty); } if (orderBy != null) { return orderBy(query).ToList(); } else { return query.ToList(); } } public virtual IEnumerable<TEntity> GetWithQuery(string queryString, params object[] par) { return dbSet.SqlQuery(queryString, par); } public virtual int Execute(string queryString, params object[] par) { return context.Database.ExecuteSqlCommand(queryString, par); } public virtual TEntity GetByID(object id) { return dbSet.Find(id); } public virtual void Insert(TEntity entity) { dbSet.Add(entity); } public virtual void Delete(object id) { TEntity entityToDelete = dbSet.Find(id); Delete(entityToDelete); } public virtual void Delete(TEntity entityToDelete) { if (context.Entry(entityToDelete).State == EntityState.Detached) { dbSet.Attach(entityToDelete); } dbSet.Remove(entityToDelete); } public virtual void Update(TEntity entityToUpdate) { dbSet.Attach(entityToUpdate); context.Entry(entityToUpdate).State = EntityState.Modified; } protected virtual void Dispose(bool disposing) { if (!this.disposed) { if (disposing) { context.Dispose(); } } this.disposed = true; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } } }
Outros Repositórios Específicos
namespace Exemplo.Repository { public class BannersRepository : GenericRepository<Banner> { private ExemploContext dbContext; public BannersRepository(ExemploContext context) : base(context) { this.dbContext = context; } public IEnumerable<Banner> GetBannersOnline() { var itens = from item in dbContext.Banners where item.Publicar select item; return itens; } } }
Exemplo de uso
namespace Exemplo.Controllers { public class CidadesController : Controller { private readonly IUnitOfWork Repository = new ExemploUnitOfWork(); public ActionResult Index() { //Busca cidades com id > 50 e inclui o estado. var cidades = Repository.CidadesRepository.Get(includeProperties: "Estado", filter: p => p.nIdCidade > 50); //Banners tem todos os metodos do genetico e os especificos var banners = Repository.BannersRepository.GetBannersOnline(); return View(); } } }
-
Para não afetar muito o projeto, o que eu fiz.
Eu criei uma classe que todos meus repositórios vão herdar para controlar o contexto.
Nessa classe, eu verifico se existe o contexto, senão crio um novo, isso baseado numa implementação do UnitOfWork que funciona com threads, e que pelo que entendi, ele cria uma thread(controlando com Guid)
Acha viável? Senão usarei seu exemplo.
- Editado Alexsander Rodrigues terça-feira, 3 de dezembro de 2013 13:03
-
Faz o seguinte eu nunca fiz assim é novo isso pra mim! (UNITOFWORK com Threads)
eu acho legal essa troca de informações para um fim em comum quem sabe melhor desempenho!!!
O Exemplo que te passei é injeção de dependencia e não afeta em nada o projeto, mas,
o que você relatou eu nunca fiz compartilha para gente testar quem sabe não é a melhor solução e mais performática!!!
-
No meu exemplo o Context é instanciado no construtor do UnitOfWork e passado via construtor para cada repositório.
Assim tenho somente uma instancia do Context distribuída entre os repositórios.
Como você falou que trabalha com vários Contexts, não pode fazer o mesmo processo? basta passar no construtor do repositório a instancia correta.
Ex: new GenericRepository<Cidade>(Context1), new GenericRepository<Cidade>(Context2), etc
-
-