11

当我进行延迟加载时,注入数据访问依赖项的正确方法是什么?

例如我有以下类结构

class CustomerDao : ICustomerDao
  public Customer GetById(int id) {...}

class Transaction {
  int customer_id; //Transaction always knows this value
  Customer _customer = null;
  ICustomerDao _customer_dao;
  Customer GetCustomer() {
    if(_customer == null)
      _customer = _customer_dao.GetById(_customer_id);
    return _customer
  }

如何获取对 _customer_dao 的引用到事务对象中?如果我希望事务至少看起来像 POCO,那么为构造函数要求它似乎没有任何意义。让 Transaction 对象直接引用 Inversion of Control Container 可以吗?这也显得很尴尬。

NHibernate 之类的框架如何处理这个问题?

4

3 回答 3

7

我建议一些不同的东西......使用延迟加载类:

public class Lazy<T>
{
   T value;
   Func<T> loader;

   public Lazy(T value) { this.value = value; }
   public Lazy(Func<T> loader { this.loader = loader; }

   T Value
   {
     get 
    {
       if (loader != null)
       {
         value = loader();
         loader = null;
       }

       return value;
    }

    public static implicit operator T(Lazy<T> lazy)
    {
        return lazy.Value;
    }

    public static implicit operator Lazy<T>(T value)
    {
        return new Lazy<T>(value);
    }
}

一旦你得到它,你就不需要在你的对象中注入 dao 了:

public class Transaction
{
    private static readonly Lazy<Customer> customer;

    public Transaction(Lazy<Customer> customer)
    {
      this.customer = customer;
    }

    public Customer Customer
    {
       get { return customer; } // implicit cast happen here
    }
}

创建未绑定到数据库的 Transcation 对象时:

new Transaction(new Customer(..)) // implicite cast 
                                  //from Customer to Lazy<Customer>..

从存储库中的数据库重新生成事务时:

public Transaction GetTransaction(Guid id)
{
   custmerId = ... // find the customer id 
   return new Transaction(() => dao.GetCustomer(customerId));
}

发生了两件有趣的事情: - 您的域对象可以在有或没有数据访问的情况下使用,它变得对数据访问无知。唯一的小转折是允许传递一个提供对象而不是对象本身的函数。- Lazy 类是内部可变的,但可以用作不可变值。readonly 关键字保持其语义,因为它的内容不能从外部更改。

当您希望该字段可写时,只需删除 readonly 关键字。当分配一个新值时,由于隐式转换,将使用新值创建一个新的 Lazy。

编辑:我在这里写了博客:

http://www.thinkbeforecoding.com/post/2009/02/07/Lazy-load-and-persistence-ignorance

于 2009-02-06T22:41:52.433 回答
1

我通常像上面那样在构造函数中进行依赖注入,但是只有在像下面这样调用“get”时才采取行动,从而使延迟加载更进一步。不确定这是否是您正在寻找的纯方法,但它确实在 1 步中消除了“脏”构造函数 DI/Lazy Loading ;)

public class Product
{
    private int mProductID;
    private Supplier mSupplier;
    private ISupplierService mSupplierService;

    public Product()
    {
      //if you want your object to remain POCO you can use dual constr
      //this constr will be for app use, the next will be for testing
    } 

    public Product(ISupplierService SupplierService)
    {
        mSupplierService = SupplierService;
    }

    public Supplier Supplier {
        get {
            if (mSupplier == null) {
                if (mSupplierService == null) {
                    mSupplierService = new SupplierService();
                }
                mSupplier = mSupplierService.GetSupplierByProductID(mProductID);
            }
            return mSupplier;
        }
        set { mSupplier = value; }
    }
}
于 2008-09-25T01:50:49.030 回答
1

我对 POCO 这个术语不是很熟悉,但我读过的定义似乎通常遵循对象独立于某些更大框架的精神。

也就是说,无论你如何分割它,如果你正在执行依赖注入,你将与那些功能被注入的类进行协作,以及将依赖对象粘在其中的东西,无论它是一个完整的注入框架或只是一些汇编类。

对我自己来说,将 IOC 容器的引用注入到一个类中似乎很奇怪。我更喜欢在构造函数中进行注入,代码如下所示:

public interface IDao<T>
{
    public T GetById(int id);
}


public interface ICustomerDao : IDao<Customer>
{
}

public class CustomerDao : ICustomerDao
{
    public Customer GetById(int id) 
    {...}
}

public class Transaction<T> where T : class
{

    int _id; //Transaction always knows this value
    T _dataObject;
    IDao<T> _dao;

    public Transaction(IDao<T> myDao, int id)
    {
        _id = id;
        _dao = myDao;
    }

    public T Get()
    {
        if (_dataObject == null)
            _dataObject = _dao.GetById(_id);
        return _dataObject;
    }
}
于 2008-09-25T02:36:42.557 回答