LINQ a SQL y el patrón de repositorio


Siento que estoy corriendo en círculos. Parece que no puedo decidir qué patrón de repositorio correcto está usando LINQ para SQL . Si usted está familiarizado con Rob Conery MVC Storefront verá que su implementación envuelve los modelos generados por LINQ con otra clase y trata al generado por LINQ simplemente como un objeto de transferencia de datos (DTO). Se ve algo como esto:

//Custom wrapper class.
namespace Data
{
    public class Customer
    {
         public int Id {get;set;}
         public string Name {get;set;}
         public IList<Address> Addresses {get;set;}
    }
}

//Linq-Generated Class - severly abbreviated
namespace SqlRepository
{
    public class Customer
    {
         public int Id {get;set;}
         public string Name {get;set;}
         public EntitySet<Address> {get;set;}
    }
}

//Customer Repository
namespace SqlRepository
{
    public class UserRepository : IUserRepository
    {
        private _db = new DB(); //This is the Linq-To-Sql datacontext

        public IQueryable GetCusomters()
        {
            return
                from c in _db.Customers
                select new Customer // This is the wrapper class not the gen'd one
                {
                   Id = c.Id,
                   Name = c.Name,
                   Addresses = new LazyList(c.Addresses)
                };
        }

¿Cuál es la ventaja de hacerlo de esta manera (usando una clase wrapper), a diferencia de la forma en que Mike Hadlow sugiere en Usando el patrón IRepository con LINQ a SQL en su versión de IRepository donde solo devuelve los objetos DTO del repositorio?

¿Dónde se debe aplicar y verificar la lógica de negocio? ¿Está esto en una capa separada todos juntos llamados por el repositorio al guardar / actualizar, o está integrado en la clase wrapper?

Author: Peter Mortensen, 2009-01-20

3 answers

La cosa es esto, LINQ to SQL no es un verdadero Mapeador de Relaciones de objetos (OR), es un generador de capas de acceso a datos. Puede hacer que sea un OR profundizando a mano editando archivos XML y jugando con SqlMetal y demás, pero donde brilla es como un DAL .

La idea detrás de un OR es esta. Tiene su base de datos SQL y sus objetos de dominio. Para diseñar una base de datos correctamente, vas a hacer cosas (como la normalización) que lógicamente no se traducen en un modelo de objetos correctamente diseñado, y viceversa. Esto se llama" Falta de coincidencia de impedancia", el papel de un OR es lidiar con esa falta de coincidencia de una manera limpia, efectiva y eficiente. La interacción menos dolorosa con la base de datos es casi una cosa secundaria.

La idea detrás de un repositorio es que encapsula toda la lógica de persistencia y las dependencias de la infraestructura del resto de su aplicación. Cuando su aplicación necesita un objeto de cliente, no debería tener que saber si está llegando desde SQL Server, MySQL, un archivo XML o ASP.NET Membresía. Una vez que tenga ese desacoplamiento, cualquier cambio que realice en su historia de persistencia no tendrá efecto en el resto de su aplicación.

Con eso en mente, queda más claro por qué hizo lo que hizo. LINQ to SQL se utiliza para generar el DAL, pero lo único que se debe saber sobre el DAL es el repositorio, por lo que se realiza una traducción a sus objetos de dominio. De esa manera puede refactorizar su modelo de dominio sin preocuparse por su historia de persistencia, y puede refactorizar su base de datos sin preocuparse por los efectos de ondulación a través de su aplicación. También podría comenzar a programar en lógica de negocios antes de decidir sobre preguntas como qué OR usar o incluso dónde almacenar sus datos.

Si tuviera que usar un OR real (como NHibernate), ese código de asignación se maneja en otro lugar (ya sea en XML o en clases de bootstrapping). Creo que LINQ to SQL (y Robs open source DAL, SubSonic) son grandes proyectos, pero más diseñado para aplicaciones más pequeñas de dos niveles donde algo como el patrón de repositorio es excesivo. El escaparate también es un buen ejemplo de por qué la complejidad adicional de NHibernate puede ser importante. Podría haberse ahorrado mucho código yendo con algo construido para manejar ese tipo de escenario, en lugar de hacerlo todo manualmente.

 48
Author: Matt Briggs,
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-08-12 15:02:36

Depende de dónde se definan los DTOs y cómo se desee probarlo. Si utiliza DBML, LINQ to SQL desea generar los objetos de datos en la capa de datos. Mientras que LINQ to SQL soporta ignorancia de persistencia, no se sale de su camino para hacerlo fácil. Entity Framework no lo soporta en absoluto.

Esto significa que en el modelo estándar, su capa de datos está definiendo todas las entidades de dominio, lo cual es complicado si desea probar el usuario capas de interfaz / negocio en verdadero aislamiento de la capa de datos.

Un enfoque pragmático podría ser usar las definiciones de objetos de datos de la capa de datos en pruebas unitarias, pero no el contexto de datos (es decir, ocultar el contexto de datos detrás de la interfaz del repositorio, pero exponer los tipos de entidad), pero esto está enturbiando un poco las aguas, y significa su interfaz de usuario, etc. necesidad de hacer referencia fuertemente a la capa de datos. Pero si usted piensa en esto como una " capa de modelo de dominio que pasa a contener también un repositorio implementación que podemos o no podemos estar utilizando " usted podría justificarlo.

Mantener entidades de dominio completamente separadas hace que las pruebas unitarias y la inversión de control (IoC) sean más "puras", pero aumenta la cantidad de código que tiene (de doble filo).

 13
Author: Marc Gravell,
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-08-12 15:08:15

¿Los objetos generados son serializables? Tuve la impresión de que no lo eran. Es solo un caso de aislamiento, como dijo Marc Gravel anteriormente.

¿Qué pasa si cambia el repositorio y tiene un MySQL, Oracle, archivos XML, servicio Web o cualquier proveedor de datos (Repositorio)? ¿Usted estaría atado a la asamblea de LINQ a SQL para hacer referencia a las entidades, derecho? Lo cual, por supuesto, no querrías.

 2
Author: Andrei Rînea,
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-08-12 15:09:32