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 のように見せたい場合、あまり意味がないように思えます。Inversion of Control Container を直接 Transaction オブジェクトに参照させてもよろしいですか? それもまたむずかしそうです。

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

データベースにバインドされていないトランザクション オブジェクトを作成する場合:

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

2 つの興味深いことが起こります: - ドメイン オブジェクトは、データ アクセスの有無にかかわらず使用できます。データ アクセスを無視します。唯一のちょっとしたひねりは、オブジェクト自体の代わりにオブジェクトを与える関数を渡すことができるようにすることです。- 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」が呼び出されたときにのみ動作することで、遅延読み込みをさらに一歩進めます。これがあなたが探している純粋なアプローチであるかどうかはわかりませんが、「汚れた」コンストラクターDI/Lazy Loadingを1ステップで排除します;)

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 に答える