16

我试图找出最干净的方法来做到这一点。

目前我有一个客户对象:

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 映射文件非常整洁。在我按照教程设置会话和存储库工厂之后,提取数据库记录非常简单。

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

我的原始方法包括数据库上的存储过程,由 DAL 对象调用,它将结果集解析为我的域/业务对象。

我用 30 毫秒的时间记录了我最初的方法来获取一条客户记录。然后,我将 nhibernate 方法计时为 3000 毫秒以获取相同的记录。

我错过了什么吗?或者使用这条休眠路由是否有很多开销?

否则我喜欢代码的简洁性:

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

我遵循的示例让我创建了一个帮助类来帮助管理会话,也许这就是我得到这个开销的原因?

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

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

仍然愿意接受建议!


更新。

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

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

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

4

4 回答 4

6

如果您的配置现在可以工作,为什么要搞砸呢?听起来您并没有确定代码的任何特定需求或问题。

我敢肯定,一堆 OO 类型可能会挤在一起,并在这里提出各种重构建议,以便尊重正确的职责和角色,甚至有人可能会试图硬塞一两个设计模式。但是您现在拥有的代码很简单,听起来没有任何问题 - 我会说离开它。

于 2009-03-13T23:17:38.513 回答
5

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

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

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 进行配置,现在的障碍比以往任何时候都低。

于 2009-03-13T23:34:53.103 回答
2

这对您来说可能过于激进,并不能真正解决问题,但是完全废弃您的数据层并选择 ORM 怎么样?您将节省大量代码冗余,而在 DAL 上花费一周左右会带来。

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

  • 您的 Email 类中的服务对象 - 例如 EmailService - 在构造函数或属性中实例化。通过 email.Service.GetById(id) 等实例访问
  • 电子邮件上的静态方法,例如 Email.GetById(id) ,这是一种类似的方法
  • 一个完全独立的静态类,基本上是一个外观类,例如 EmailManager,具有像 EmailManager.GetById(int) 这样的静态方法
  • 处理实例的 ActiveRecord 模式,例如 email.Save() 和 email.GetById()
于 2009-03-13T23:40:31.250 回答
2

您的应用程序很可能在事务脚本中设置了域逻辑。对于使用事务脚本的 .NET 实现,Martin Fowler 建议使用表数据网关模式。.NET 为这种模式提供了很好的支持,因为表数据网关模式非常适合记录集,Microsoft 使用其 DataSet 类型的类来实现记录集。

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

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

于 2009-03-13T23:43:53.677 回答