Pregunta

Tengo un modelo de dominio que tiene el concepto de un Editor y un Proyecto.

Un editor posee varios proyectos, y un proyecto no solo tiene un propietario de editor, sino también varios miembros del editor. Por lo tanto, un editor también tiene un número de "unido" Proyectos.

Estoy adoptando un enfoque DDD para modelar esto y usando el patrón Repository para persistencia. Sin embargo, todavía no he asimilado el patrón lo suficientemente bien como para determinar cómo debo hacer esto.

Estoy trabajando asumiendo que el Editor y el Proyecto están potencialmente en el mismo agregado, siendo la raíz Editor. Por lo tanto, puedo obtener un Editor y luego enumerar sus Proyectos, y desde allí podría enumerar los Editores miembros de los Proyectos.

Sin embargo, si solo se me permite recuperar editores de mi repositorio, ¿no significa esto que tengo que cargar todos los proyectos del repositorio cuando obtengo el editor que los posee? Y si quiero cargar de forma diferida a los Editores miembros, ¿el Proyecto también necesita una referencia al repositorio?

Alternativamente, si divido el agregado y tengo un repositorio de editor y un repositorio de proyecto, ¿cómo debo manejar una transacción entre los dos, como cuando se agrega un nuevo proyecto a un editor? Por ejemplo:

Editor e = new Editor("Editor Name");
editorRepository.Add(e);

Project p = e.CreateProject("Project Name");
projectRepository.Add(p);    // These two lines
editorRepository.Save(e);    // should be atomic

¿Estoy malinterpretando la intención del patrón del Repositorio?

¿Fue útil?

Solución

  

¿Estoy malinterpretando la intención del patrón del Repositorio?

Voy a decir '' sí '', pero sé que yo y todas las personas con las que he trabajado han preguntado lo mismo por la misma razón ... '' No estás pensando en 4a dimensión , Marty " ;.

Simplifiquemos un poco y sigamos con los constructores en lugar de crear métodos primero:

Editor e = new Editor("Editor Name");
e = editorRepository.Add(e);

Project p = new Project("Project Name", e);
p = projectRepository.Add(p);

Debajo, el repositorio de su proyecto siempre está almacenando un propietario válido ( p.EditorId ) en los datos del proyecto a medida que se crea, y sin importar cómo vuelva a llenar los proyectos de un editor, estará allí. Es por eso que es una buena práctica poner todas las propiedades requeridas en los constructores. Si no desea pasar todo el objeto, solo lo hará el e.Id .

  

¿Y si quiero cargar de forma diferida a los Editores miembros, el Proyecto también necesita una referencia al repositorio?

Ahora, en cuanto a cómo volver a llenar los proyectos de un editor a pedido, tiene un par de opciones dependiendo de lo que esté buscando. Straight Repository dice que quieres:

IEnumerable<Project> list = projectRepository.GetAllProjects()
                                .Where(x => x.editorId == e.Id);

¿Pero dónde ponerlo? No dentro de Project, o Editor, tienes razón, o tendrán que acceder a los repositorios y eso no es bueno. El fragmento anterior está acoplado libremente, pero no es reutilizable por sí solo. Acaba de llegar a los límites del Patrón de repositorio.

El siguiente es una Capa de Adaptador para su aplicación, con una fuente compartida de repositorios ( StaticServiceWrapper ) y algún tipo de objeto EditorAdapter (o Aggregate o como quiera llamarlos) o ahora usted puede mezclar métodos de extensión que pueden comunicarse con todos los repositorios necesarios con fluidez. No lo he hecho exactamente de esta manera en un sistema de producción, pero para mostrarle un ejemplo conciso:

public static class Aggregators
{
    // one to one, easy
    public static Editor GetOwner(this Project p)
    {
        return StaticServiceWrapper.editorRep.GetEditorById(p.editorId);
    }

    // one to many, medium
    public static IEnumerable<Project> GetProjects(this Editor e) 
    { 
        return StaticServiceWrapper.projectRep.GetAllProjects()
                .Where(x => x.editorId == e.Id);
    }

    // many to many, harder
    public static IEnumerable<Editor> GetMembers(this Project p)
    {
        var list = StaticServiceWrapper.projectMemberMap.GetAllMemberMaps()
                        .Where(x => x.projectId == p.projectId);

        foreach ( var item in list )
            yield return StaticServiceWrapper.editorRep.GetEditorById(item.editorId);
    }
}

Básicamente, una vez que se realiza el repositorio GetAll, GetById, Add, Update, Remove Object, debe dejar las asociaciones solas y avanzar por la jerarquía de objetos / capas a las partes divertidas como Adaptadores y cachés y Business Logic ( " ¡Oh, mi! " ).

Otros consejos

¿Qué hay de dividir las responsabilidades en un EditorOwner y un EditorMember?

Sin conocer su dominio, me imagino que tendrían diferentes responsabilidades: por ejemplo, el EditorOwner podría ser bastante rico (y podría ser la raíz agregada), pero el Proyecto solo necesita saber una cantidad limitada sobre su miembros, por lo que el objeto EditorMember puede ser bastante ligero.

Estos objetos de dominio también pueden relacionarse con Usuarios, pero eso estaría en otro contexto.

¿Eso ayuda a las cosas, o simplemente lo hace más complicado?

Depende de las necesidades de su aplicación. Si es un gran problema cargar todos los proyectos para un editor determinado, intente un patrón de carga diferida como Proxy virtual .

Con respecto a la carga perezosa de los Editores miembros de un Proyecto, si usa Virtual Proxy, no veo ningún problema al inyectar el proxy con el EditorRepository ya que no considero que el proxy sea parte del dominio.

Si divide el Agregado, puede investigar el patrón Unidad de trabajo como uno solo solución a la atomicidad. Sin embargo, este problema no es exclusivo de DDD y estoy seguro de que hay otras soluciones para el comportamiento transaccional.

Aquí tiene 2 relaciones diferentes, una para la propiedad y otra para la membresía.

La relación de propiedad es simple para muchos (un propietario para cada proyecto). La relación de membresía es de muchos a muchos (muchos Editores por proyecto, muchos proyectos por editor).

Puede proporcionar una propiedad de Propietario en la clase Proyecto, y proporcionar un método en el Repositorio de proyectos para obtener todos los proyectos propiedad de un Editor específico.

Para las muchas relaciones, proporcione una propiedad Miembros en la clase Proyecto y un método en el Depósito de proyectos para obtener todos los proyectos que contengan el Editor especificado como miembro.

También parece que los Editores y los Proyectos son entidades, probablemente dividiría el agregado, pero quizás esos términos tienen un significado específico en su contexto que lo convierten en subentidades de un agregado.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top