2009-03-13 18 views
15

Estoy tratando de encontrar la manera más limpia de hacerlo.Mejor "patrón" para la capa de acceso a datos al objeto comercial

Actualmente tengo un objeto de cliente:

public class Customer 
{ 
    public int Id {get;set;} 
    public string name {get;set;} 
    public List<Email> emailCollection {get;set} 
    public Customer(int id) 
    { 
     this.emailCollection = getEmails(id); 
    } 
} 

Entonces mi correo electrónico objeto también es bastante básico.

public class Email 
{ 
    private int index; 
    public string emailAddress{get;set;} 
    public int emailType{get;set;} 
    public Email(...){...} 
    public static List<Email> getEmails(int id) 
    { 
     return DataAccessLayer.getCustomerEmailsByID(id); 
    } 
} 

El DataAccessLayer conecta actualmente a la base de datos, y utiliza un SqlDataReader para iterar sobre el conjunto de resultados y crea nuevos objetos de correo electrónico y los añade a una lista que se devuelve cuando haya terminado.

Entonces, ¿dónde y cómo puedo mejorar esto?

¿Debo tener mi DataAccessLayer en su lugar devolver una DataTable y dejarla en el objeto Email para analizar y devolver una lista al cliente?

Supongo que "Factory" es probablemente la palabra incorrecta, pero ¿debería tener otro tipo de EmailFactory que toma una DataTable de DataAccessLayer y devuelve una lista al objeto Email? Supongo que ese tipo de sonido suena redundante ...

¿Es esta la práctica correcta tener mi Email.getEmails (id) como un método estático?

Tal vez me estoy tirando tratando de encontrar y aplicar el mejor "patrón" a lo que normalmente sería una tarea simple.

Gracias.


Seguimiento

He creado un ejemplo de trabajo donde mi dominio objeto/Negocios extrae un registro de cliente de identificación de una base de datos existente. Los archivos de mapeo xml en nhibernate son realmente geniales. Después de seguir un tutorial para configurar las sesiones y las fábricas de repositorios, extraer los registros de la base de datos fue bastante sencillo.

Sin embargo, he notado un gran golpe de rendimiento.

Mi método original consistía en un Procedimiento almacenado en la base de datos, que fue llamado por un objeto DAL, que analizó el conjunto de resultados en mi dominio/objeto comercial.

Me sincronicé con mi método original en 30ms para obtener un solo registro de cliente. Luego sincronicé el método nhibernate en tomar 3000ms para obtener el mismo registro.

¿Echo de menos algo? ¿O hay muchos gastos indirectos usando esta ruta de nhibernate?

De lo contrario me gusta la limpieza del código:

protected void Page_Load(object sender, EventArgs e) 
{ 
    ICustomerRepository repository = new CustomerRepository(); 
    Customer customer = repository.GetById(id); 
} 

public class CustomerRepository : ICustomerRepository 
     { 
      public Customer GetById(string Id) 
      { 
       using (ISession session = NHibernateHelper.OpenSession()) 
       { 
        Customer customer = session 
             .CreateCriteria(typeof(Customer)) 
             .Add(Restrictions.Eq("ID", Id)) 
             .UniqueResult<Customer>(); 
        return customer; 
       } 
      } 
     } 

El example I followed me había crear una clase de ayuda para ayudar a administrar la sesión, tal vez por eso me estoy poniendo esta sobrecarga?

public class NHibernateHelper 
    { 
     private static ISessionFactory _sessionFactory; 
     private static ISessionFactory SessionFactory 
     { 
      get 
      { 
       if (_sessionFactory == null) 
       { 
        Configuration cfg = new Configuration(); 
        cfg.Configure(); 
        cfg.AddAssembly(typeof(Customer).Assembly); 
        _sessionFactory = cfg.BuildSessionFactory(); 
       } 
       return _sessionFactory; 
      } 

     } 

     public static ISession OpenSession() 
     { 
      return SessionFactory.OpenSession(); 
     } 
    } 

Con la aplicación en la que estoy trabajando, la velocidad es esencial. Y, en última instancia, pasarán muchos datos entre la aplicación web y la base de datos. Si a un agente le toma 1/3 de segundo obtener un registro de cliente en lugar de 3 segundos, eso sería un gran golpe.Pero si estoy haciendo algo raro y este es un costo de configuración inicial de una sola vez, entonces valdría la pena si el rendimiento fuera tan bueno como la ejecución de procedimientos almacenados en la base de datos.

¡Aún abierto a sugerencias!


Actualizado.

Estoy cancelando mi ruta ORM/NHibernate. Descubrí que el rendimiento es demasiado lento para justificar su uso. Las consultas básicas de los clientes simplemente toman demasiado tiempo para nuestro entorno. 3 segundos en comparación con respuestas por debajo del segundo es demasiado.

Si queríamos consultas lentas, mantendríamos nuestra implementación actual. La idea de reescribirlo fue aumentar drásticamente los tiempos.

Sin embargo, después de haber jugado con NHibernate la semana pasada, ¡es una gran herramienta! Simplemente no se ajusta a mis necesidades para este proyecto.

+0

Barry- Sí, está funcionando muy bien como es ahora. Lo único que se me ocurre es que mi DataAccessLayer devuelva una DataTable, de modo que pueda hacer comprobaciones de validación en mi Business Layer (es decir, objeto de correo electrónico) en lugar de hacerlo en la capa de acceso a datos. –

+1

El ejemplo que publicó es el clásico "modelo de dominio anémico". Según su ejemplo, ni siquiera necesita un objeto comercial. Un objeto comercial debe contener la lógica comercial, y el tuyo no. –

Respuesta

6

Si la configuración que tiene funciona ahora, ¿por qué meterse con ella? No parece que identifiques necesidades o problemas particulares con el código tal como está.

Estoy seguro de que un montón de tipos OO podrían agruparse y sugerir varias refactorizaciones aquí para que se respeten las responsabilidades y los roles correctos, y alguien podría incluso tratar de calzarse en uno o dos patrones de diseño. Pero el código que tienes ahora es simple y parece que no tiene ningún problema, yo diría que déjalo.

+0

Me considero un tipo OO, pero estoy totalmente de acuerdo. La solución actual es tan simple que incluso yo puedo entenderla, lo que definitivamente es una buena calidad. – Treb

+2

Una sugerencia es agregar más comportamiento "comercial" al objeto comercial. Parece que el objeto comercial no se está utilizando correctamente arriba. –

5

Implementé una capa DAL básicamente haciendo lo que hace NHibernate pero manualmente. Lo que NHibernate hace es crear una clase Proxy que herede de su objeto de Dominio (que debería tener todos sus campos marcados como virtuales). Todo el código de acceso a datos entra en anulaciones de propiedad, es bastante elegante en realidad.

Lo simplifiqué un tanto al hacer que mis repositorios rellenaran las propiedades simples y solo utilizaran un proxy para la carga diferida. Lo que terminó es un conjunto de clases de esta manera:

public class Product { 
    public int Id {get; set;} 
    public int CustomerId { get; set;} 
    public virtual Customer Customer { get; set;} 
} 
public class ProductLazyLoadProxy { 
    ICustomerRepository _customerRepository; 
    public ProductLazyLoadProxy(ICustomerRepository customerRepository) { 
    _customerRepository = customerRepository; 
    } 
    public override Customer { 
    get { 
     if(base.Customer == null) 
     Customer = _customerRepository.Get(CustomerId); 
     return base.Customer 
    } 
    set { base.Customer = value; } 
    } 
} 
public class ProductRepository : IProductRepository { 
    public Product Get(int id) { 
    var dr = GetDataReaderForId(id); 
    return new ProductLazyLoadProxy() { 
     Id = Convert.ToInt(dr["id"]), 
     CustomerId = Convert.ToInt(dr["customer_id"]), 
    } 
    } 
} 

Pero después de escribir sobre 20 de ellas me dio por vencido y aprendió NHibernate, con Linq2NHibernate para consultar y FluentNHibernate para la configuración en la actualidad los obstáculos son más bajos que nunca.

2

Esto puede ser demasiado radical para usted y realmente no resuelve la pregunta, pero ¿qué hay de descartar completamente la capa de datos y optar por un ORM? Ahorrará mucha redundancia de código que le llevará una semana más o menos en un DAL.

Dejando eso de lado, el patrón que está utilizando se asemeja a un patrón de depósito, más o menos. Yo diría que sus opciones son

  • Un objeto de servicio en su clase de correo electrónico, digamos EmailService, instanciado en el constructor o una propiedad. Acceder a través de una instancia como email.Service.GetById (id)
  • un método estático en el correo electrónico, como Email.GetById (id) que es un enfoque similar
  • una clase estática completamente separado que es básicamente una clase de fachada, EmailManager, por ejemplo, con métodos estáticos como EmailManager.GetById (int)
  • El patrón ActiveRecord en el que se trata de una instancia, como correo electrónico. Save() y correo electrónico.GetById()
2

Es muy probable que su aplicación tenga su configuración de lógica de dominio en transaction scripts. Para las implementaciones de .NET que utilizan secuencia de comandos de transacción, Martin Fowler recomienda el uso del patrón table data gateway. .NET proporciona un buen soporte para este patrón porque el patrón de puerta de enlace de datos de tabla es excelente con record set, que Microsoft implementa con sus clases de tipo DataSet.

Varias herramientas en el entorno de Visual Studio deben aumentar su productividad. El hecho de que DataSets se pueda unir fácilmente a varios controles (como DataGridView) lo convierte en una buena opción para las aplicaciones basadas en datos.

Si su lógica de negocio es más compleja que unas pocas validaciones, una domain model se convierte en una buena opción. ¡Tenga en cuenta que un modelo de dominio viene con un conjunto completamente diferente de requisitos de acceso a datos!

Cuestiones relacionadas