¿Cómo usar el patrón de repositorio correctamente?


Me pregunto cómo debería agrupar mis repositorios? Como de los ejemplos que he visto en el asp.net mvc y en mis libros utilizan básicamente un repositorio por tabla de base de datos. Pero eso parece un montón de repositorios que te lleva a tener que llamar a muchos repositorios más tarde para burlarse y esas cosas.

Así que supongo que debería agruparlos. Sin embargo, no estoy seguro de cómo agruparlos.

Ahora mismo hice un repositorio de registro para manejar todas mis cosas de registro. Obstante hay como 4 tablas que necesito actualizar y antes tenía 3 repositorios para hacer esto.

Por ejemplo, una de las tablas es una tabla de licencias. Cuando se registran, miro su clave y la compruebo para ver si existe en la base de datos. Ahora, ¿qué pasa si necesito comprobar esta clave de licencia o algo de esa tabla en algún otro lugar otro registro?

Un punto podría ser login(comprobar si la clave no ha caducado).

Entonces, ¿qué haría en esta situación? Reescribir el código de nuevo(break DRY)? Trate de merege estos 2 repositorios juntos y la esperanza de que ninguno de los métodos son necesarios en algún otro punto del tiempo(como tal vez podría tener un método que comprueba si se utiliza el nombre de usuario - tal vez voy a necesitar que en otro lugar).

También si los fusiono, necesitaría 2 capas de servicio para ir al mismo repositorio, ya que creo que tener toda la lógica para 2 partes diferentes de un sitio sería largo y tendría que tener nombres como ValidateLogin(), ValdiateRegistrationForm (), ValdiateLoginRetrievePassword () y etc.

¿O llamar al Repositorio de todos modos y tener un nombre que suene raro?

Simplemente parece difícil hacer un repositorio que tenga un nombre lo suficientemente general como para que pueda usarlo para muchos puntos de su aplicación y aún tenga sentido y no creo que llamar a otro repositorio en un repositorio sea una buena práctica?

Author: chobo2, 2009-09-30

7 answers

Una cosa que hice mal cuando jugaba con el patrón de repositorio - al igual que usted, pensé que la tabla se relaciona con el repositorio 1:1. Cuando aplicamos algunas reglas de Dominio Driven Design - problema de agrupación de repositorios a menudo desaparece.

El repositorio debe ser por Raíz agregada y no por tabla. Significa-si la entidad no debe vivir sola (es decir, si tiene un Registrant que participa en particular Registration) - es solo una entidad, no necesita un repositorio, debe ser actualizado / creado / recuperado a través del repositorio de la raíz agregada a la que pertenece.

Por supuesto, en muchos casos, esta técnica de reducir el número de repositorios (en realidad, es más una técnica para estructurar su modelo de dominio) no se puede aplicar porque cada entidad se supone que es una raíz agregada (que depende en gran medida de su dominio, solo puedo proporcionar conjeturas ciegas). En su ejemplo - License parece ser una raíz agregada porque necesita poder verificarlas sin contexto de Registration entidad.

Pero eso no nos restringe a los repositorios en cascada (Registration al repositorio se le permite hacer referencia al repositorio License si es necesario). Eso no nos limita a hacer referencia al repositorio License (preferible - a través de IoC) directamente desde el objeto Registration.

Simplemente trate de no conducir su diseño a través de complicaciones proporcionadas por las tecnologías o malentendidos algo. Agrupar repositorios en ServiceX solo porque no quieres construir 2 repositorios no es una buena idea.

Mucho mejor sería darle un nombre propio - RegistrationService es decir,

Pero los servicios deben evitarse en general - a menudo son causa que conduce a modelo de dominio anémico.

EDITAR:
Comience a usar el CoI. Realmente alivia el dolor de inyectar dependencias.
En lugar de escribir:

var registrationService = new RegistrationService(new RegistrationRepository(),  
      new LicenseRepository(), new GodOnlyKnowsWhatElseThatServiceNeeds());

Usted será capaz de escribir:

var registrationService = IoC.Resolve<IRegistrationService>();

P. S. Sería mejor usar el llamado localizador de servicios comunes pero eso es solo un ejemplo.

 39
Author: Arnis Lapsa,
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-11-22 09:27:33

Una cosa que he comenzado a hacer para abordar esto es desarrollar servicios que envuelvan N repositorios. Esperemos que sus marcos de DI o IoC puedan ayudar a hacerlo más fácil.

public class ServiceImpl {
    public ServiceImpl(IRepo1 repo1, IRepo2 repo2...) { }
}

¿Tiene sentido? Además, entiendo que hablando de servicios en esta mansión puede o no cumplir con los principios DDD, solo lo hago porque parece funcionar.

 5
Author: neouser99,
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
2009-09-30 01:12:14

Lo que estoy haciendo es que tengo una clase base abstracta definida de la siguiente manera:

public abstract class ReadOnlyRepository<T,V>
{
     V Find(T lookupKey);
}

public abstract class InsertRepository<T>
{
     void Add(T entityToSave);
}

public abstract class UpdateRepository<T,V>
{
     V Update(T entityToUpdate);
}

public abstract class DeleteRepository<T>
{
     void Delete(T entityToDelete);
}

Luego puede derivar su repositorio de la clase base abstracta y extender su repositorio único mientras los argumentos genéricos difieran, por ejemplo;

public class RegistrationRepository: ReadOnlyRepository<int, IRegistrationItem>,
                                     ReadOnlyRepository<string, IRegistrationItem> 

Etc....

Necesito los repositorios separados porque tenemos restricciones en algunos de nuestros repositorios y esto nos da la máxima flexibilidad. Espero que esto ayude.

 2
Author: Michael Mann,
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
2009-09-30 02:55:49

Tengo esto como mi clase de repositorio y sí me extiendo en el repositorio de tabla / área, pero aún así a veces tengo que romper SECO.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MvcRepository
{
    public class Repository<T> : IRepository<T> where T : class
    {
        protected System.Data.Linq.DataContext _dataContextFactory;

        public IQueryable<T> All()
        {
            return GetTable.AsQueryable();
        }

        public IQueryable<T> FindAll(Func<T, bool> exp)
        {
            return GetTable.Where<T>(exp).AsQueryable();
        }

        public T Single(Func<T, bool> exp)
        {
            return GetTable.Single(exp);
        }

        public virtual void MarkForDeletion(T entity)
        {
            _dataContextFactory.GetTable<T>().DeleteOnSubmit(entity);
        }

        public virtual T CreateInstance()
        {
            T entity = Activator.CreateInstance<T>();
            GetTable.InsertOnSubmit(entity);
            return entity;
        }

        public void SaveAll()
        {
            _dataContextFactory.SubmitChanges();
        }

        public Repository(System.Data.Linq.DataContext dataContextFactory)
        {
            _dataContextFactory = dataContextFactory;
        }

        public System.Data.Linq.Table<T> GetTable
        {
            get { return _dataContextFactory.GetTable<T>(); }
        }

    }
}

EDITAR

public class AdminRepository<T> : Repository<T> where T: class
{
    static AdminDataContext dc = new AdminDataContext(System.Configuration.ConfigurationManager.ConnectionStrings["MY_ConnectionString"].ConnectionString);

    public AdminRepository()
        : base( dc )
    {
    }

También tengo un datacontext que fue creado usando Linq2Sql.clase dbml.

Así que ahora tengo un repositorio estándar implementando llamadas estándar como All y Find y en mi AdminRepository tengo llamadas específicas.

No responde a la pregunta de SECO aunque no creo.

 2
Author: griegs,
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
2009-09-30 05:45:28

Aquí hay un ejemplo de una implementación de repositorio genérica usando FluentNHibernate. Es capaz de persistir en cualquier clase para la que haya escrito un mapeador. Incluso es capaz de generar su base de datos basada en las clases mapper.

 1
Author: James Jones,
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
2010-02-18 04:28:41

El patrón del repositorio es un patrón de diseño incorrecto. Trabajo con muchos proyectos. Net antiguos y este patrón generalmente causa errores de" Transacciones distribuidas"," Reversión Parcial "y" Grupo de conexiones agotado " que podrían evitarse. El problema es que el patrón intenta manejar conexiones y transacciones internamente, pero éstas deben ser manejadas en la capa de Controlador. También EntityFramework ya abstrae mucha de la lógica. Yo sugeriría usar el patrón de servicio en lugar de reutilizar código compartido.

 1
Author: ColacX,
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
2016-02-01 16:27:55

Le sugiero que mire Sharp Architecture. Sugieren usar un repositorio por entidad. Lo estoy usando actualmente en mi proyecto y wery satisfecho con los resultados.

 0
Author: Sly,
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
2009-09-30 06:42:31