2010-05-07 16 views
14

En mi experiencia en la creación de aplicaciones web, siempre he usado un enfoque de n niveles. Un DAL que obtiene datos del DB y rellena los objetos, y BLL que obtiene objetos del DAL y realiza cualquier lógica de negocios requerida en ellos, y el sitio web que obtiene sus datos de visualización del BLL. Recientemente comencé a aprender LINQ, y la mayoría de los ejemplos muestran las consultas que ocurren directamente desde los códigos subyacentes de la aplicación web (es posible que solo haya visto ejemplos demasiado simplificados). En las arquitecturas de n niveles, esto siempre se vio como un gran no-no.
No estoy seguro de cómo diseñar una nueva aplicación web. He estado usando Server Explorer y el diseñador de dbml en VS2008 para crear las relaciones de objeto y dbml. Me parece un poco incierto si el dbml se consideraría la capa DAL, si el sitio web debe llamar a métodos dentro de un BLL, que luego haría las consultas LINQ, etc.
¿Cuáles son algunas de las mejores prácticas de arquitectura general, o enfoques para crear una solución de aplicación web usando LINQ to SQL?Mejores prácticas de aplicación web de LINQ a SQL

Respuesta

16

Me temo que de hecho has visto ejemplos demasiado simplificados. LINQ to SQL (System.Data.Linq) es su capa DAL. Las clases que genera L2S son su dominio (pero no debe confundir con Domain-Driven Design). Además de eso, aún puede escribir su Business Layer.

Siempre trato de evitar que se filtre el LINQ a SQL DataContext en la capa de presentación (su aplicación web). Por lo tanto, no debería poder crear o confirmar un DataContext. Tampoco debe devolver objetos IQueryable<T> a la capa de presentación. IMO, la capa empresarial debe tener control total sobre la vida útil de DataContext (unidad de trabajo) y la forma de las consultas SQL.

Sin embargo, hay varios sabores. Algunas personas carpa para relajar estas limitaciones. Otros incluso van mucho más allá. Depende de tu propio gusto y del tamaño de la aplicación. Mientras más grande sea la aplicación, más se justifica agregar capas de abstracción.

Al no permitir que IQueryable s y otras cosas relacionadas con los datos abandonen la capa empresarial, terminará teniendo algunos desafíos interesantes. Por ejemplo, la capa de presentación debe indicar a la capa empresarial cómo ordenar los resultados. Si bien podría dejar que la capa de presentación clasifique los resultados, esto significaría que tendría que obtener todos los datos de la base de datos y la página en la capa de presentación, lo que daría lugar a un sistema con muy mal rendimiento. Hay varias soluciones a este problema. En todos los casos, deberá informar a la capa empresarial cómo ordenar los resultados por usted. Las soluciones se pueden encontrar aquí en SO cuando busca LINQ dynamic sort. Yo mismo he escrito una solución de este tipo, here.

Otro reto que no permite que IQueryable s deje su BL traerá es que los objetos de dominio a menudo no pueden salir de su BL. La mayoría de sus objetos de dominio LINQ a SQL contendrán propiedades cargadas perezosas (por ejemplo, colecciones a otros objetos de dominio). Sin embargo, cuando el DataContext tiene el control de Business Layer, se eliminará antes de devolver los resultados a la capa de presentación. Cuando la presentación no accede a una propiedad con carga diferida, se producirá una excepción porque ya se ha eliminado el DataContext. Cuando elimine el DataContext en su capa empresarial, este comportamiento es, por supuesto, "por diseño".Permitir que la capa de presentación obtenga propiedades cargadas perezosas significa que el BL pierde el control sobre las consultas que se envían a la base de datos, perdiendo así el control del rendimiento.

Para resolver este problema, debe devolver objetos de transferencia de datos (DTO) del BL a la capa de presentación. Un DTO contendrá solo datos y no interno DataContext, y no tendrá propiedades de carga diferida. Un DTO puede formatearse especialmente para la solicitud real en cuestión. Los DTO, por supuesto, conducen a la sobrecarga de codificación ellos mismos, por lo que el tamaño de su sistema y las necesidades de rendimiento deben justificarlo. Para hacerlo más fácil, tiendo a poner métodos de proyección estáticos en un DTO. Si bien esto no se ajusta al principio separation of concerns, creo que es una solución muy práctica. Mira por ejemplo en este CustomerDTO:

public class CustomerDTO 
{ 
    public int CustomerId { get; set; } 
    public string Name { get; set; } 
    // City is flatterned from Address.City. 
    public string City { get; set; } 

    internal static IQueryable<CustomerDTO> AsDTO(IQueryable<Customer> customers) 
    { 
     return 
      from customer in customers 
      select new CustomerDTO() 
      { 
       CustomerId = customer.Id, 
       Name = customer.Name, 
       City = customer.Address.City 
      }; 
    } 
} 

Este DTO define una AsDTO método interno, que es capaz de convertir una colección de Customer objetos de dominio a una colección de CustomerDTO DTO. Esto hace que la conversión de objetos de dominio a DTO sea mucho más fácil. Mira, por ejemplo, en este método de BL:

public static CustomerDTO[] GetCustomersByCountry(string country) 
{ 
    using (var db = ContextFactory.CreateContext()) 
    { 
     IQueryable<Customer> customers = 
      (from customer in db.Customers 
      where customer.Address.Country == country 
      orderby customer.Name, customer.Id); 

     return CustomerDTO.AsDTO(customers).ToArray(); 
    } 
} 

Lo bueno de este enfoque es que cuando nos fijamos en la consulta SQL, verá que sólo el ID de cliente, nombre y la Ciudad de la tabla de direcciones le ser recuperado de la base de datos. Esto se debe a que el método AsDTO traduce uno IQueryable a otro, permitiendo que LINQ to SQL realice la operación total en la base de datos.

Espero que esto dé algunas ideas de lo que puede hacer. Por supuesto, esta es mi opinión sobre el tema y las cosas que he encontrado prácticas en mi situación.

+0

gracias por la respuesta completa. Me estremezco al acceder a los datos en la capa de presentación. Tiendo a hacer la mayor parte de mi clasificación en la capa de datos actualmente, así que eso no será un problema. No había oído hablar antes de DTO, suena como algo para investigar más. – derek

+0

DTO a menudo se considera que tienen una gran sobrecarga. Son especialmente útiles cuando se envían datos a través del cable (por ejemplo, cuando se tienen servicios web WCF o ASMX). Por ejemplo, cuando lees "Microsoft .NET: aplicaciones de arquitectura para la empresa" de Dino Esposito, verás que Dino piensa que normalmente le dan demasiados gastos cuando transfieres objetos entre capas del mismo dominio de aplicación. Si bien tiene razón en esto, todavía los encontré útiles en ese escenario en particular y veo que los gastos generales se reducen cuando la tecnología mejora ... – Steven

+0

Por ejemplo, las nuevas construcciones de lenguaje C# como las propiedades automáticas facilitan la definición de DTO y herramienta de refactorización como Refactor! Pro permite generar automáticamente un DTO a partir de una definición de tipo anónimo dentro de una consulta LINQ. – Steven

4

El LINQ to SQL es el acceso DB en la implementación DAL, si desea separar entre DAL y BLL. Si tiene una Aplicación Web menos compleja (y tampoco tiene la intención de cambiar los back-ends de DB), puede alejarse sin DAL/BLL explícito y hacer todo lo que esté en el código. LINQ to SQL funciona muy bien para operaciones de solo lectura, pero se siente un poco más trabajo para implementar operaciones de escritura.

Cuestiones relacionadas