2008-09-24 6 views
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 컨테이너를 직접 참조하도록해도 괜찮습니까? 그것은 또한 어색해 보인다.

NHibernate와 같은 프레임 워크는 어떻게 처리합니까?

답변

1

나는 일반적으로 위와 같이 생성자에서 의존성 주입을 수행하지만, 아래처럼 "get"이 호출 될 때만 연기하여 게으른로드를 취합니다. 이것이 당신이 찾고있는 순수한 접근 방식이지만, 1 단계에서 "더러운"생성자 DI/게으른로드를 제거 않는 경우 확실하지,

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

이 더 우아한 될 수 있지만, 보통 내가 시간을 구현입니다 : 나는 여기에 대해 블로그. 그것은 또한 당신의 코드를 리다이렉션에 의한 lazy-loading을 처리 할 수있는 좀 더 높은 레벨의 라이브러리로 개방합니다. – ojrac

+2

위와 같은 발언 : 서비스 (특히 DAO)를 주입하는 것은 좋은 생각이 아닙니다. 의존성없이 객체를 사용할 수 없도록 만들고 테스트하기가 매우 어렵습니다. 그것은 끔찍한 끈기를 깨뜨립니다. – thinkbeforecoding

+0

나는 개인적으로 속성 ('mSupplier') *이로드 될 수도있는 시나리오를 피하려고하지만 그렇지 않을 수도 있습니다. 엔티티를 사용할 때마다 걱정이됩니다. 누군가 불완전하게로드 했습니까? 예를 들어'mSupplier'는 null이지만 그럴 수 없었습니까? 'mSupplier'에 널 체크가 필요합니까? 이러한 null 검사가 지연로드를 트리거 할 가능성이 있습니까? (틀림없이 나는 여전히 성배를 찾고 있습니다.) – Timo

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

그래서 기본적으로 생성자를 통해 삽입해야한다고 말하고 있습니까? 아마,하지만 어색해 보인다. –

+1

서비스 (특히 DAO)를 주입하는 것은 좋은 생각이 아닙니다. 의존성없이 객체를 사용할 수 없도록 만들고 테스트하기가 매우 어렵습니다. 그것은 끔찍한 끈기를 깨뜨립니다. – thinkbeforecoding

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

+0

어쨌든 이것은 집계를 올바르게 정의하고 지연로드를 피하는 것이 좋습니다 ... – thinkbeforecoding

관련 문제