2010-11-09 17 views
5

Me gustaría implementar la arquitectura típica de tres capas. Mi enfoque actual es el siguientePregunta de diseño Objetos POCO/Acceso DAL

  • DAL - con EF 4.0 y repositorios para cada una de mis entidades. acceso a través de las interfaces
  • Estaba pensando en usar objetos POCO. Mi primera pregunta sería ¿dónde debería poner esos archivos ? En un conjunto al que hacen referencia todos los demás proyectos?
  • BLL - ¿Cómo obtengo los datos del DAL al BLL y finalmente a la GUI ? Es una buena forma si tuviera un montón de clases de gerentes allí, como CustomerManager en el BLL. Estas clases podrían acceder al depósito correspondiente en el BLL y luego pasar los objetos de la interfaz gráfica de usuario

o crees que es mejor poner el repositorio en la BLL y acceder a ellos directamente desde mi buttoneventhandler digamos?

Esperemos que se puede aportar algo de luz a la oscuridad

+0

Si una de nuestras respuestas ayudó, por favor márquela como aceptada – Basic

Respuesta

6

Tenemos los repositorios de la DAL. El BLL hace referencia a los repositorios a través de una interfaz, por lo que los repositorios están vinculados al DAL pero están desacoplados del BLL. No sé de ninguna razón por la cual los repositorios no podrían estar directamente en el BLL. Los tenemos en el DAL ya que no ponemos NINGUNA lógica en ellos. Luego tenemos "Administradores" en el BLL que envuelven los repositorios y manejan la lógica específica de la entidad.

FWIW en realidad tenemos un genérico Repository(Of IEntity) y usamos la unidad para instanciar el repositorio apropiado según sea necesario, es muy compacto y bastante elegante. Todas nuestras entidades POCO implementan IEntity que contiene Id, CreatedDate, etc. que son comunes a TODAS nuestras entidades. Esto le da a algunos otros beneficios cuando se necesita para manejar cualquier tipo de entidad genérica - CreatedDate se establece por el repositorio cuando CreateInstance() se llama, ModifiedDate es fijado por el propio contexto en que se cometió una entidad con un estado de Modified

Guardamos entidades en un proyecto separado: el DAL necesita poder hacer referencia a ellas, al igual que el BLL. No los quiere en el DAL ya que intercambiar el DAL causaría problemas. No puede ponerlos en el BLL o recibe una referencia circular. La configuración de las entidades puede vivir en el DAL ya que es fuente de datos específicos.

Intentamos adherirnos a la BLL teniendo en cuenta las primitivas y las entidades que regresan. Tenga cuidado al mantener las entidades en la IU por mucho tiempo, especialmente en una aplicación web, ya que puede tener un contexto diferente bajo el DAL para cuando devuelve la entidad a la BLL para su procesamiento (es decir, a través de solicitudes almacenadas en sesión o similares) puede dar lugar a todo tipo de entidades de vinculación/separación divertidas de contextos y le pierde algunos beneficios, como el seguimiento de cambios.

Espero que ayude, pero si quieres alguna aclaración, que me haga saber

+0

Gracias por su respuesta. ¿Están sus clases gerenciales estáticas? – Developer23

+0

En realidad, no, nuevamente utilizamos la inyección de unidad/dependencia para devolver una referencia a una sola instancia. Esto se debe a que los gerentes dependen de los repos que a su vez dependen del contexto que no es estático. Probablemente puedas evitar esto pero no lo hemos hecho. – Basic

+0

Una pregunta más trivial. ¿Cuál es su recomendación en términos de nombres? ¿Utiliza algo como CustomerManager o como RPM1984 escribió CustomerService? – Developer23

1

Puede mantener esta muy simple, manteniendo sus repositorios y Pocos en el mismo proyecto. Este sería esencialmente su modelo de dominio de datos. Sus POCO son públicas y también lo son sus interfaces de repositorio. Debes mantener tus repositorios de hormigón internos a este proyecto.

Su BLL podría ser un clásico Fachada o Localizador de Servicio. Este proyecto daría masajes a sus datos y aplicaría las reglas comerciales pertinentes antes de entregarlos a la IU. Esto también sería responsable de validar los datos provenientes de la interfaz de usuario antes de enviarlos a DAL.

+0

Enfoque interesante. ¿Dónde vive la configuración de su entidad? es decir, tipos de datos SQL para propiedades, Índices? – Basic

+0

No estoy seguro si entiendo su pregunta correctamente. Todo acceso a SQL sería abstraído por su Modelo de Datos (.edmx). – Praveen

+0

Ah, bien - Utilizamos primero el código EF4 para que nuestras entidades sean clases que creamos a mano y elaboramos manualmente nuestras configuraciones (claves, FK, etc.) esto significa que podemos mantener las cosas específicas de SQL como tipos de datos vinculados al DAL pero tienen las entidades POCO genéricas. – Basic

3

Esta es nuestra configuración:

Company.Project.Domain.Model  (POCOs) 
Company.Project.Business.Services (BLL) 
Company.Project.Data.Repositories (Repository) 
Company.Project.Web    (Presentation) 
  • POCO'S están en su propia asamblea. Referencias nada y Referenciado por todos.
  • BLL ejecuta consultas en repositorios, aplica reglas de negocio e hidratación. Devoluciones ICollection<T> o T. Repositorios de referencias (a través de IRepository<T> interfaz genérica) y POCOs.
  • Repositorio es un conjunto de clases genéricas que implementan IRepository<T> para proporcionar una persistencia básica contra la tienda subyacente. Buscar, Agregar, Eliminar, etc. Devoluciones IQueryable. Referencias POCO's, Referenciado por BLL.
  • La presentación es UI. Referencias POCOs y BLL.

El resultado final es un enfoque similar al de una pila, y porque básicamente todo es a través de interfaces (y registros DI), la flexibilidad es enorme.

Tenemos repositorios falsos que se inyectan en los proyectos de prueba a través de DI y Repositorios de Entity Framework que se inyectan en el BLL a través de DI.

Ejemplo flujo de interfaz de usuario -> DB:

// "Company.Project.Web.ProductsController.cs" 
public class ProductsController : BaseController 
{ 
    private IProductService _productService; 

    public ProductsController(IProductService productService) 
    { 
     this._productService = productService; // DI makes me happy :) 
    } 

    public ActionResult GetOrdersForProduct(Product product) 
    { 
     var orders = _productService.GetOrders(product); 
     return View(orders); 
    } 
} 

// "Company.Project.Business.Services.ProductService.cs" 
public class ProductService : IProductService 
{ 
    private IRepository<Product> _productRepository; 

    public ProductService (IRepository<Product> productRepository) 
    { 
     this._productRepository = productRepository; // DI makes me happy :) 
    } 

    public ICollection<Orders> GetOrdersForProduct(Product product) 
    { 
     return _productRepository 
       .Find() 
       .ForProduct(product) // IQueryable<Product> pipe/extension filter 
       .ToList(); 
    } 
} 

// "Company.Project.Data.Repositories.GenericRepository.cs 
public class GenericRepository<T> : IRepository<T> where T : class 
{ 
    private IObjectSet<T> _objectSet; 

    public GenericRepository(IUnitOfWork unitOfWork) 
    { 
     CurrentContext = unitOfWork as SqlServerUnitOfWork; 
    } 

    public IQueryable<T> Find() 
    { 
     return CurrentContext.GetEntitySet<T>(); 
    } 

    protected SqlServerUnitOfWork CurrentContext { get; private set; } 

    protected IObjectSet<T> CurrentEntitySet 
    { 
     // some plularization smarts in "SqlServerUnitofWork.cs", to dynamically pull 
     // back entity set based on T. 
     get { return _objectSet ?? (_objectSet = CurrentContext.GetEntitySet<T>()); } 
    } 
} 

Como se puede ver, soy un fanboy DI.

+1

Simplemente una sugerencia de rendimiento - En lugar de devolver ICollection intente devolver IQueryable - Esto le permite cargar los elementos en la lista reduciendo gastos generales si la interfaz de usuario solo necesita s subconjunto (por ejemplo, para paginación) – Basic

+0

@Basiclife - lea mi parte sobre la Repositorio. Estoy haciendo exactamente eso. IMO deben diferirse al BLL, no más allá de la IU, de lo contrario, uno podría obtener resultados inesperados. La paginación es fácil, solo pase el número de página/paginación al método en el BLL, que omite/toma el iqueryable del repositorio. – RPM1984

+0

Y por cierto, eso no es una carga diferida, eso es ** ejecución diferida **. Tenga cuidado de no confundir a los dos. Inhabilito la carga diferida en EF, y estoy ansioso por cargar las entidades que requiere el BLL usando '.Include'. – RPM1984