none
Desacoplar interfaces del repositorio del dominio con los repositorios de la capa de datos RRS feed

  • Pregunta

  • Buenas Noches, esperando bastante de la ayuda de la comunidad ya que llevo mucho tiempo peliando con esto

    Tengo una capa de dominio con 3 proyectos que llame Domain

    Uno se llama Models que contiene las entidades generadas por EF

    El otro se llama IRepositories  contiene dos interfaces que definen lo que el dominio quiere de la capa de datos

    el otro se llama AgentDomain que contendrá el acceso a una Interface del Irepositories creada con Unity.Ioc.

    Ahora en la capa de Datos que llame DataPersistence

    tengo dos Proyectos uno que se llama DataAccess que solo contiene el archivo.edmx

    y otro que es Repositories que contiene la implementacion a los datos.

    les empiezo a mostrar el codigo

    Empecemos por la capa Domain.IRepositories

    namespace EasySchool.Domain.IRepositories
    {
    	public interface IPatternRepository<TEntity> where TEntity : class
    	{
    		void Create(TEntity entity);
    		void CreateRange(IEnumerable<TEntity> entities);
    		IEnumerable<TEntity> Read();
    		void Update(TEntity entity);
    		void UpdateRange(IEnumerable<TEntity> entities);
    		void Delete(TEntity entity);
    		void DeleteRange(IEnumerable<TEntity> entities);
    		IQueryable Queryable();
    		IQueryable Queryable(string query, params object[] parameters);
    	}
    }


    y la otra Interface

    namespace EasySchool.Domain.IRepositories
    {
    	public interface IUnityOfWork
    	{
    		IPatternRepository<Sex> SexesRepository { get; }
    		IPatternRepository<PersonalRecord> PersonalRecords { get; }
    
    		void SabeChange();
    	}
    }


    ahora la dll AgentDomain que usara esta interface con unity.Ioc

    namespace EasySchool.Domain.DomainAgents
    {
    	public class ServiceAgent
    	{
    		private IUnityOfWork unityOfWork;
    
    		public ServiceAgent()
    		{
    			// Se construye la interface con UNity
    		}	
    	}
    }

    hay yo digo bien chido todo, el problema es cuando quiero hacer la implementacion

    voy a poner el codigo que implementa IPatternRepository

    using EasySchool.Domain.IRepositories;
    
    namespace EasySchool.DataPersistence.Repositories
    {
    	public class PatternRepository : IPatternRepository<Sex>
    	{
    		public void Create(Sex entity)
    		{
    			throw new NotImplementedException();
    		}
    
    		public void CreateRange(IEnumerable<Sex> entities)
    		{
    			throw new NotImplementedException();
    		}
    
    		public void Delete(Sex entity)
    		{
    			throw new NotImplementedException();
    		}
    
    		public void DeleteRange(IEnumerable<Sex> entities)
    		{
    			throw new NotImplementedException();
    		}
    
    		public IQueryable Queryable()
    		{
    			throw new NotImplementedException();
    		}
    
    		public IQueryable Queryable(string query, params object[] parameters)
    		{
    			throw new NotImplementedException();
    		}
    
    		public IEnumerable<Sex> Read()
    		{
    			throw new NotImplementedException();
    		}
    
    		public void Update(Sex entity)
    		{
    			throw new NotImplementedException();
    		}
    
    		public void UpdateRange(IEnumerable<Sex> entities)
    		{
    			throw new NotImplementedException();
    		}
    	}
    }

    Aqui hay un grave problema me pide forzosamente que le pase una entidad, en donde iva el TEntity yo no quiero eso,

    yo quiero un repository generico uno de esta manera

    namespace EasySchool.DataPersistence.Repositories
    {
    	public class PatternRepository<TEntity> where TEntity : class
    	{
    		private readonly EasySchoolEntities context;
    		private readonly DbSet<TEntity> dbSet;
    
    		public PatternRepository(EasySchoolEntities context)
    		{
    			this.context = context;
    			this.dbSet = context.Set<TEntity>();
    		}
    
    		void Create(TEntity entity)
    		{
    			dbSet.Add(entity);
    		}
    
    		void CreateRange(IEnumerable<TEntity> entities)
    		{
    			foreach (var entity in entities)
    			{
    				Create(entity);
    			}
    		}
    
    		IEnumerable<TEntity> Read()
    		{
    			return dbSet;
    		}
    
    		void Update(TEntity entity)
    		{
    			dbSet.Attach(entity);
    			context.Entry(entity).State = EntityState.Modified;
    		}
    
    		void UpdateRange(IEnumerable<TEntity> entities)
    		{
    			foreach (var entity in entities)
    			{
    				this.Update(entity);
    			}
    		}
    
    		void Delete(TEntity entity)
    		{
    			if (context.Entry(entity).State == EntityState.Detached)
    			{
    				dbSet.Attach(entity);
    			}
    			dbSet.Remove(entity);
    		}
    
    		void DeleteRange(IEnumerable<TEntity> entities)
    		{
    			foreach (var entity in entities)
    			{
    				this.Update(entity);
    			}
    		}
    
    		IQueryable Queryable()
    		{
    			return dbSet;
    		}
    
    		IQueryable Queryable(string query, params object[] parameters)
    		{
    			return dbSet.SqlQuery(query, parameters).AsQueryable();
    		}
    	}
    }

    entonces se me ocurrio ponerle 

    <TEntity> where TEntity : class

    y el IPatternRepository de esta manera

    public class PatternRepository<TEntity> where TEntity : class, IPatternRepository<TEntity>
    	{
    		private readonly EasySchoolEntities context;
    		private readonly DbSet<TEntity> dbSet;
    
    		public PatternRepository(EasySchoolEntities context)
    		{
    			this.context = context;
    			this.dbSet = context.Set<TEntity>();
    		}
    
    		void Create(TEntity entity)
    		{
    			dbSet.Add(entity);
    		}
    
    		void CreateRange(IEnumerable<TEntity> entities)
    		{
    			foreach (var entity in entities)
    			{
    				Create(entity);
    			}
    		}
    
    		IEnumerable<TEntity> Read()
    		{
    			return dbSet;
    		}
    
    		void Update(TEntity entity)
    		{
    			dbSet.Attach(entity);
    			context.Entry(entity).State = EntityState.Modified;
    		}
    
    		void UpdateRange(IEnumerable<TEntity> entities)
    		{
    			foreach (var entity in entities)
    			{
    				this.Update(entity);
    			}
    		}
    
    		void Delete(TEntity entity)
    		{
    			if (context.Entry(entity).State == EntityState.Detached)
    			{
    				dbSet.Attach(entity);
    			}
    			dbSet.Remove(entity);
    		}
    
    		void DeleteRange(IEnumerable<TEntity> entities)
    		{
    			foreach (var entity in entities)
    			{
    				this.Update(entity);
    			}
    		}
    
    		IQueryable Queryable()
    		{
    			return dbSet;
    		}
    
    		IQueryable Queryable(string query, params object[] parameters)
    		{
    			return dbSet.SqlQuery(query, parameters).AsQueryable();
    		}
    	}

    aquí lo extraño es que no me pidió que implementara IPatternRepository los métodos los puse yo llamándose igual pero no me los puso ni me los exigió

    ahora les muestro la otra clase UnityOfWork que implementa IUnityOfWork

    public class UnityOfWork : IUnityOfWork
    	{
    		private readonly EasySchoolEntities context;
    		private PatternRepository<Sex> sexesRepository;
    		private PatternRepository<PersonalRecord> personalRecordsRepository;
    
    		public UnityOfWork()
    		{
    			this.context = new EasySchoolEntities();
    		}
    
    		public IPatternRepository<Sex> SexesRepository
    		{
    			get
    			{
    				if (this.sexesRepository == null)
    				{
    					this.sexesRepository = new PatternRepository<Sex>(this.context);
    				}
    				return this.sexesRepository;
    			}
    		}
    
    		public IPatternRepository<PersonalRecord> PersonalRecords
    		{
    			get
    			{
    				if (this.personalRecordsRepository == null)
    				{
    					this.personalRecordsRepository = new PatternRepository<PersonalRecord>(this.context);
    				}
    				return this.personalRecordsRepository;
    			}
    		}
    
    		public void SabeChange()
    		{
    			this.context.SaveChanges();
    		}
    	}

    y hay estan los problemas

    y esta otra

    Hay disculpen el codigo excesivo pero no sabia como preguntar este error sin mostrar todo

    estoy seguro que el error e por que la clase PatternRepository IMplementa la interface y tambien <TEntity> pero eso es 

    justo lo que quiero no quiero hacer un repositorio por entidad si se puede reutilizar pues mejor pero quiero que este definido

    desde el dominio para poder desacoplar con Ioc Espero sus prontos comentarios

    De antemano muchas Gracias

    viernes, 29 de diciembre de 2017 5:17

Respuestas

  • hola

    que pasa si usas

    public class PatternRepository<TEntity> : IPatternRepository<TEntity> where TEntity : class
    {

    de esta forma puedes definir la implementacion de la interfaz generica en una clase tambien generica

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    • Marcado como respuesta niqel viernes, 29 de diciembre de 2017 13:40
    viernes, 29 de diciembre de 2017 12:20

Todas las respuestas

  • Hola, buenos días. En la declaración del PatternRepository, no tienes que exigir que TEntity sea IPatternRepository. Es de lo que se está quejando el compilador, las clases Sex y PersonalRecord no son IPatternRepository.

    Si lo cambiás por esto debería funcionar:

    public class PatternRepository<TEntity> where TEntity : class

    Salu2


    viernes, 29 de diciembre de 2017 6:13
  • okey, pero si hago eso funcionara el desacople con unity ya que PatternRepository no estaria implementando a la interface IPatternRepository, ya lo cambie

    public class UnityOfWork : IUnityOfWork
    	{
    		private readonly EasySchoolEntities context;
    		private PatternRepository<Sex> sexesRepository;
    		private PatternRepository<PersonalRecord> personalRecordsRepository;
    
    		public UnityOfWork()
    		{
    			this.context = new EasySchoolEntities();
    		}
    
    		public IPatternRepository<Sex> SexesRepository
    		{
    			get
    			{
    				if (this.sexesRepository == null)
    				{
    					this.sexesRepository = new PatternRepository<Sex>(this.context);
    				}
    				return this.sexesRepository;
    			}
    		}
    
    		public IPatternRepository<PersonalRecord> PersonalRecords
    		{
    			get
    			{
    				if (this.personalRecordsRepository == null)
    				{
    					this.personalRecordsRepository = new PatternRepository<PersonalRecord>(this.context);
    				}
    				return this.personalRecordsRepository;
    			}
    		}
    
    		public void SabeChange()
    		{
    			this.context.SaveChanges();
    		}
    	}
    en mi clase UnityOfWork Que implementa IUnityOfWork pss marca error ya que en el get  pedia un IPatternRepository. recuerda que las interfaces son para implementar Unity.Ioc y desacoplar totalmente los datos del negocio

    viernes, 29 de diciembre de 2017 7:33
  • hola

    que pasa si usas

    public class PatternRepository<TEntity> : IPatternRepository<TEntity> where TEntity : class
    {

    de esta forma puedes definir la implementacion de la interfaz generica en una clase tambien generica

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    • Marcado como respuesta niqel viernes, 29 de diciembre de 2017 13:40
    viernes, 29 de diciembre de 2017 12:20
  • Leandro como siempre dando una gran respuesta deberás muchas gracias se corrigió todo

    muchas gracias

    viernes, 29 de diciembre de 2017 13:40