c# - El mejor "patrón" para Data Access Layer to Business Object
asp.net design-patterns (4)
Esto puede ser demasiado radical para usted y realmente no resuelve la pregunta, pero ¿qué hay de desechar completamente su capa de datos y optar por un ORM? Ahorrará una gran cantidad de redundancia de código que el gasto de una semana más o menos en un DAL traerá.
Aparte de eso, el patrón que estás usando se parece a un patrón de repositorio, más o menos. Yo diría que tus opciones son
- Un objeto de servicio en su clase de correo electrónico, por ejemplo, Servicio de correo electrónico, instanciado en el constructor o en una propiedad. Se accede 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 separada que es básicamente una clase de fachada, por ejemplo, EmailManager, con métodos estáticos como EmailManager.GetById (int)
- El patrón de ActiveRecord en el que está tratando con una instancia, como email.Save () y email.GetById ()
Estoy tratando de descubrir la forma más limpia de hacer esto.
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 objeto de correo electrónico 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 actualmente se conecta 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 agrega a una lista que devuelve cuando termina.
Entonces, ¿dónde y cómo puedo mejorar esto?
¿Debo tener mi DataAccessLayer en lugar de devolver un DataTable y dejarlo en el objeto de correo electrónico 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 tome un DataTable del DataAccessLayer y devuelva una Lista al objeto de Email? Supongo que ese tipo de sonidos son redundantes ...
¿Es esto incluso una práctica adecuada tener mis Email.getEmails (id) como un método estático?
Es posible que me esté desechando tratando de encontrar y aplicar el mejor "patrón" a lo que normalmente sería una tarea simple.
Gracias.
Seguir
Creé un ejemplo de trabajo en el que mi objeto Dominio / Negocio extrae un registro de cliente por ID desde una base de datos existente. Los archivos de mapeo xml en nhibernate son realmente aseados. Después de seguir un tutorial para configurar las sesiones y las fábricas de repositorios, la extracción de registros de la base de datos fue bastante sencilla.
Sin embargo, he notado un gran éxito 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 objeto de dominio / negocio.
Registre mi método original en la toma de 30 ms para obtener un solo registro de cliente. Luego, cronometré el método de inhibición al tomar 3000 ms para obtener el mismo registro.
¿Me estoy perdiendo de algo? ¿O hay solo una gran cantidad de gastos generales al utilizar esta ruta 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 ejemplo que seguí me hizo crear una clase de ayuda para ayudar a administrar la sesión, ¿quizás es por eso que estoy obteniendo 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, finalmente, muchos datos pasarán entre la aplicación web y la base de datos. Si un agente necesita 1/3 de segundo para recuperar el registro de un cliente en lugar de los 3 segundos, sería un gran golpe. Pero si estoy haciendo algo raro y este es un costo inicial de instalación, entonces valdría la pena si el rendimiento fuera tan bueno como ejecutar procedimientos almacenados en la base de datos.
¡Todavía abierto a sugerencias!
Actualizado.
Estoy desechando mi ruta ORM / NHibernate. Encontré que el rendimiento es demasiado lento para justificar su uso. Las consultas básicas de los clientes solo llevan demasiado tiempo para nuestro entorno. 3 segundos en comparación con las respuestas de un segundo es demasiado.
Si quisiéramos consultas lentas, simplemente 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 satisface mis necesidades para este proyecto.
He implementado una capa DAL básicamente haciendo lo que NHibernate hace manualmente. Lo que NHibernate hace es crear una clase Proxy que hereda de su objeto de dominio (que debe tener todos sus campos marcados como virtuales). Todo el código de acceso a los datos entra en las anulaciones de propiedad, en realidad es bastante elegante.
Simplifiqué esto un poco al hacer que mis repositorios llenen las propiedades simples por sí mismos y solo usando un proxy para la carga diferida. Lo que terminé es un conjunto de clases como esta:
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 alrededor de 20 de estos, simplemente abandoné y aprendí NHibernate, con Linq2NHibernate para consultas y FluentNHibernate para configuración hoy en día los obstáculos son más bajos que nunca.
Lo más probable es que su aplicación tenga su configuración de lógica de dominio en los scripts de transacción . Para las implementaciones .NET que utilizan secuencias de comandos de transacción, Martin Fowler recomienda el uso del patrón de puerta de enlace de datos de la tabla . .NET proporciona un buen soporte para este patrón porque el patrón de la puerta de enlace de datos de la tabla es excelente con el conjunto de registros , que Microsoft implementa con sus clases de tipo DataSet.
Varias herramientas dentro del entorno de Visual Studio deberían aumentar su productividad. El hecho de que los DataSets puedan ser fácilmente vinculados a varios controles (como el DataGridView) hace que sea una buena opción para aplicaciones basadas en datos.
Si su lógica empresarial es más compleja que algunas validaciones, un modelo de dominio 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!
Si la configuración que tienes funciona ahora, ¿por qué meterte con ella? No suena como si estuvieras identificando alguna necesidad particular o problema con el código tal como está.
Estoy seguro de que un montón de tipos de OO podrían reunirse y sugerir varias refactorizaciones aquí para que se respeten las responsabilidades y los roles correctos, y alguien podría incluso intentar hacer calzoncillos en uno o dos patrones de diseño. Pero el código que tiene ahora es simple y parece que no tiene ningún problema, yo diría que déjelo.