数据访问层到业务对象的最佳“模式”

时间:2009-03-13 23:11:42

标签: c# asp.net design-patterns data-access-layer

我正试图找出最干净的方法。

目前我有一个客户对象:

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);
    }
}

然后我的电子邮件对象也很基本。

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);
    }
}

DataAccessLayer当前连接到数据库,并使用SqlDataReader迭代结果集并创建新的Email对象,并将它们添加到完成后返回的List。

那么我在哪里以及如何改进呢?

我是否应该让我的DataAccessLayer返回一个DataTable并将其留给Email对象进行解析并将List返回给客户?

我猜“Factory”可能是错误的单词,但是我应该使用另一种类型的EmailFactory从DataAccessLayer获取DataTable并将List返回给Email对象吗?我想这种声音多余......

将Email.getEmails(id)作为静态方法,这是否是正确的做法?

我可能只是试图找到并将最好的“模式”应用于通常只是一项简单的任务,从而让自己失望。

感谢。


跟进

我创建了一个工作示例,其中我的域/业务对象通过现有数据库中的id提取客户记录。 nhibernate中的xml映射文件非常简洁。在我按照教程设置会话和存储库工厂之后,提取数据库记录非常简单。

但是,我注意到了巨大的性能影响。

我的原始方法由DB上的存储过程组成,该过程由DAL对象调用,该对象将结果集解析为我的域/业务对象。

我用我原来的方法计时30分钟来获取单个客户记录。然后我用nhibernate方法计时3000ms来获取同样的记录。

我错过了什么吗?或者使用这种nhibernate路线会有很多开销吗?

否则我喜欢代码的清洁度:

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;
                }
            }
        }

example I followed让我创建了一个帮助类来帮助管理Session,也许这就是为什么我得到这个开销?

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();
        }
    }

随着我正在开发的应用程序,速度至关重要。最终,很多数据将在Web应用程序和数据库之间传递。如果需要一个代理1/3秒来提升客户记录而不是3秒,这将是一个巨大的打击。但是,如果我做了一些奇怪的事情,这是一次初始设置成本,那么如果性能与在DB上执行存储过程一样好,那么它可能是值得的。

仍然接受建议!


更新

我正在废弃我的ORM / NHibernate路线。我发现性能太慢,无法证明使用它。基本的客户查询对我们的环境来说需要太长时间。 3秒与亚秒响应相比太多了。

如果我们想要慢查询,我们只会保留当前的实现。重写它的想法是大幅增加时间。

然而,在过去一周玩NHibernate之后,它是一个很棒的工具!它不太适合我对这个项目的需求。

4 个答案:

答案 0 :(得分:6)

如果你现在的配置有效,为什么要乱用呢?这听起来并不像是在识别代码的任何特定需求或问题。

我确信一堆OO类型可以挤在一起并在此提出各种重构,以便正确的责任和角色得到尊重,甚至有人甚至可能试图以一两种设计模式进行设计。但是你现在拥有的代码很简单,听起来没有任何问题 - 我会说离开它。

答案 1 :(得分:5)

我实际上已经实现了一个DAL层,基本上是做NHibernate所做的但是手动。 NHibernate所做的是创建一个继承自Domain对象的Proxy类(应将其所有字段标记为虚拟)。所有数据访问代码都进入了属性覆盖,实际上非常优雅。

我通过让我的存储库自己填写简单属性并仅使用代理进行延迟加载来简化这一点。我最终得到的是一组这样的课程:

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"]),
    }
  }
}

但在写了大约20篇之后我就放弃并学习了NHibernate,Linq2NHibernate用于查询,而FluentNHibernate用于配置,现在路障比以往任何时候都要低。

答案 2 :(得分:2)

这对您来说可能过于激进,并没有真正解决问题,但如何彻底删除数据层并选择ORM?您将节省大量代码冗余,这些冗余会花费一周左右的时间来为DAL带来。

除此之外,您使用的模式类似于存储库模式。我会说你的选择是

  • 您的电子邮件类中的服务对象 - 比如EmailService - 在构造函数或属性中实例化。通过诸如email.Service.GetById(id)
  • 之类的实例访问
  • 电子邮件上的静态方法,例如Email.GetById(id),这是一种类似的方法
  • 一个完全独立的静态类,基本上是一个façade类,例如EmailManager,使用静态方法,如EmailManager.GetById(int)
  • 您正在处理实例的ActiveRecord模式,例如 email.Save()和email.GetById()

答案 3 :(得分:2)

您的应用程序很可能在transaction scripts中设置了域逻辑。对于使用事务脚本的.NET实现,Martin Fowler建议使用table data gateway模式。 .NET为这种模式提供了很好的支持,因为表数据网关模式很适合record set,Microsoft使用它的DataSet类实现。

Visual Studio环境中的各种工具应该可以提高您的工作效率。 DataSets可以轻松地数据绑定到各种控件(如DataGridView),这使它成为数据驱动应用程序的理想选择。

如果您的业务逻辑比一些验证更复杂,domain model成为一个不错的选择。请注意,域模型带有一组完整的数据访问要求!