2012-03-18 5 views
2

n 계층 응용 프로그램 아키텍처를 만들고 있습니다. 서로 다른 레이어는 서로간에 알려진 것이 없으며 레이어 간의 내부 구현 및 통신은 IoC/DI를 지원하는 매우 협소 한 인터페이스를 통해 처리됩니다.비즈니스 계층에서 데이터 계층으로 개체 유형을 전달하는 방법

이제 비즈니스 계층 (비즈니스 계층에서 정의 됨)을 데이터 계층에 전달하고 있습니다. 비즈니스 계층 자체는 데이터가 실제로 저장되는 방법과 위치를 알지 못합니다 (일반적으로 데이터베이스이지만 비즈니스 계층은이를 알지 못합니다). 비즈니스 개체는 IDataReader의 데이터 계층 트로프 구현에 전달됩니다 (이 방법은 향후 시나리오에서 대량 데이터로드를 지원합니다). 데이터 계층은 IDataReader에서 모든 데이터를 읽고 일부 저장 프로 시저를 호출하여 데이터를 데이터베이스에 저장합니다 (한 개체가 저장된 경우 IDataReader는 "한 행"을 반환 함).

실제 문제는 여기에 있습니다 :

난 그냥 데이터 계층에 IDataReader에 전달하고 해당 유형의 데이터를 분리, 데이터의 위치를 ​​결정하는 것은이 경우 가장 좋은 방법은 무엇 때문에?

예 "사용자"유형의 실제 비즈니스 개체를 데이터 계층에 전달하면 데이터 계층은 테이블 "사용자"에 데이터를 저장해야합니다. 어떤 경우에는 데이터가 비즈니스 계층의 유형과 독립적으로 다른 구조로 저장 될 수 있습니다.

현재 구현에서는 비즈니스 객체의 유형 정보를 데이터 영역에 전달하고 데이터 영역은이 유형을 검사하고 데이터를 배치 할 위치를 결정합니다.

데이터 계층에 올바른 솔루션이 들어오는 데이터를 검사하고 그 위치를 확인해야합니까? 아니면 데이터 영역에 데이터를 저장할 수있는 "장소"목록이 노출되어 있어야합니까?

미리 감사드립니다.

/명확한 설명 :

옵션 여기에서 볼 수 있습니다 : 1. 데이터 계층은 데이터 유형의 인수 (같은 인자가 검사 2. 데이터 계층을 저장할 수 있습니다 "plces"의 목록을 제공) 및 데이터를 저장할 위치를 결정하십시오

첫 번째 옵션 페널티; "사용자"유형별로 일반적으로 사용되는 구조에 "제품"유형의 비즈니스 오브젝트를 저장하려고하면 어떻게됩니까?

두 번째 옵션 페널티; "Namespace1.Namespace2.User"유형을 테이블 "User"에 데이터를 저장하는 특정 루틴에 매핑해야합니다. 그래서 수동으로 ... 각 유형에 대한 몇 가지 매핑을

/명확한 설명 2 :

지금 나는이 같은 검색을 수행합니다

service.Retrieve(typeof(Catalog), null, catalogArgs, e => catalogConverter.Read(e)); 

그래서 내가 대해서 typeof (카탈로그) 데이터 계층에 전달합니다. .. 그래서 나는 데이터 레이어에 타입 정보를 가지고있다.

이제 데이터 레이어에서 데이터베이스에서 데이터를 가져 오기 위해 열심히 노력하는 "어댑터"를 선택해야합니다. 어댑터를 선택하기 위해 엄청난 if/switch 구조를 쓸 수 있습니다 .... 또한 나는 속성을 작성하고 다음과 같이 사용할 수 있습니다 :

[TypeAdapterAttribute("Namespace1.Namespace2.Catalog, and assembly info...")] 
class CatalogAdapter { ... } 

가 그럼 난 속성 값을 지정된 형식에서 매핑을 수행하는 코드 ...

이 ...하지만 그 하드 코드 타입 문자열로 조금 부 풀리고 문제가 있습니다 ...

어떤 제안이 ...?

/명확화 3

나는이 시스템은 "플러그 비즈니스 모듈"에 의해 확장 될 수 있다는 생각을 가지고있다. 이 모듈에는 기본 비즈니스 로직으로 알 수없는 비즈니스 객체 (및 일부 로직)가 포함되며 데이터 영역에는 "플러그 된 어셈블리"에 포함 된 이러한 비즈니스 객체를 전혀 알지 못합니다. 이 외부 비즈니스 모듈에는 기본 비즈니스 계층 또는 데이터 계층에 대한 참조가 없습니다. 이 외부 어셈블리의 비즈니스 객체를 저장하면 (= 데이터 영역으로 전송) 데이터 영역은 기본적으로 EAV 스타일로 저장됩니다 (http://en.wikipedia.org/wiki/Entity%E2%80%93attribute%E2%80%). 93value_model) 데이터 구조를 자동으로 생성합니다. 이런 종류의 데이터 구조에는 성능상의 문제가있을 수 있으므로 데이터 계층에는 전용 데이터 구조 (일반적으로 해당 유형에 일대일 매핑이있는 테이블)에 특정 비즈니스 객체 유형을 저장하는 방법이 있어야합니다. 그래서 문제는 여기에, 어떻게 "선택 결정"을 구현하는 것인가? :)

아이디어는 여기에 새로운 비즈니스 객체를 많이 만들 수 있으며 데이터 영역에 아무 것도 코드하지 않고 데이터 영역에 모두 저장할 수 있다는 것입니다! 나중에 필요한 경우 선택한 비즈니스 객체에 대한 전용 데이터 구조를 만들 수 있습니다.

+0

설명 3은 완전히 새로운 전제 조건을 설명하고 완전히 새로운 질문을합니다. 속성의 수에 따라 descision을 만들 수 있습니다. 몇몇 속성 -> EAV, 많은 속성 -> 전용 모델. 이 PropertyInfo [] props = obj.GetType(). GetProperties(); '와 같은 속성을 확인할 수 있습니다. –

+0

글쎄, C3는 여전히 거의 동일한 시스템입니다. 나는 그 시스템의 목적을 명확하게하려고 노력한다. 나는 이것에 대해 조금 생각한 후에 새로운 질문을 열어 놓을 것 같아요. – Harza

답변

1

개체를 데이터 저장소에 매핑하려면 ORM (Entitiy Framework, NHibernate) 또는 마이크로 -ORM (PetaPoco, Dapper)을 사용하는 것이 좋습니다.
특정 질문이 있으면 살펴보고 촬영하십시오.

업데이트 : 내가 방금 묻는 것 같아.
각 유형에 대해 데이터 계층에 새 메소드를 정의해야합니다. 그래서 : 당신이 비즈니스 계층에서 분리 자신의 데이터베이스 계층을 만들려면

public User GetUserById(int id); 
public void SaveUser(User user); 
public Product GetProductById(int id); 
public void SaveProduct(Product product); 
+0

ORM을 사용하는 경우, "orm을 사용하여 데이터를 저장할 엔티티를 선택하는 방법"을 알아야합니다. ... – Harza

+0

모든 구현은 ORM에 따라 다르므로 일반 코드 샘플을 제공 할 수는 없습니다. 당신이하고 싶은 것 (테이블에 객체를 맵핑)은 ORM의 전체 목적입니다. PetaPoco는 매우 간단하기 때문에보세요. 설명서는 코드 샘플로 가득 찬 단일 페이지입니다. – David

+0

@Harza : 그렇습니다. 그러나 테이블과 열의 관점에서는 생각하지 않지만 비즈니스 개체와 속성에 대해서는 생각합니다. 위의 예를 참조하십시오. –

1

은 또한 계약

List<Customer> customers = DB.LoadCustomers(); 

데이터 계층은 일반적인 작업 할 수있는 별도의 어셈블리를 소개 할 수 유형 매개 변수를 입력하고 Reflection을 통해 비즈니스 오브젝트에 대한 정보를 얻으십시오. 데이터 계층에는 비즈니스 구성 요소에 대한 참조가 필요하지 않으므로 계층을 잘 분리 할 수 ​​있습니다.

List<Customer> customers = DataContext.Query<Customer>.Load(); 

또는

Customer customer = DataContext.Query<Customer>.Load(custID); 

O/R 매퍼는 일반적으로 데이터 영역을 생성하고 비즈니스 오브젝트를 채우고,이 실시 예에서이

List<Customer> customers = Context.Query<Customer>() 
    .Where(cust => cust.Name.StartsWith("A")) 
    .OrderBy(cust => cust.Name) 
    .ToList(); 

처럼 작동한다. 그렇지 않으면 비즈니스 계층은 테이블 열 이름을 알아야합니다.

(참고 : 여기서는 특정 데이터 인터페이스를 언급하지 않습니다.)


UPDATE :

당신은 또한 계약

public interface ICustomer 
{ 
    string LastName { get; set; } 
    string FirstName { get; set; } 
    ... 
} 

모두 별도의 어셈블리를 소개 할 수있는 비즈니스 계층에서 diconnected되어 자신의 데이터베이스 계층을 만들려면 데이터 계층과 비즈니스 계층은 이러한 계약을 참조하게됩니다. 데이터 계층에서

, 당신은 당신이 쓰는 것 비즈니스 계층에서

public List<T> LoadAll<T>(Func<T> create) 
{ 
    var list = new List<T>(); 
    if (T is ICustomer) { 
     string sql = "SELECT * FROM tblCustomer"; 
     ... 
     while (reader.NextResult()) { 
      ICustomer cust = (ICustomer)create(); 
      cust.FirstName = reader.GetString("FirstName"); 
      ... 
      list.Add((T)cust); 
     } 
    } else if (T is IOrder) { 
     ... 
    } 
    return list; 
} 

방법과 유사한 방법을 것

이제
List<ICustomer> customers = DbLayer.LoadAll<ICustomer>(() => new Customer()); 

, 당신의 고객을 알고 있기없이 고객과 함께 작업 할 수 데이터 층 비즈니스 계층 어셈블리에 대한 참조가 없어도됩니다.

+0

솔루션은 개체 매핑을 피하려고 시도하며 데이터는 IDataReader를 사용하여 계층 구조로 전송됩니다. 쿼리 케이스에서 데이터 레이어는 데이터 읽기 및 필요한 경우 개체 구체화에 사용할 수있는 비즈니스 계층에 IDataReader를 제공합니다. IDataReader를 사용하는 것은 문제가되지 않습니다. "실제 유형이 없으면 처리 할 데이터 유형을 데이터 계층에 알려주는 방법" – Harza

+0

다음과 같은 형식이 될 수 있습니다 :'IDataReader customers = DataLayer.LoadAll ("Customers");'. 그러나 비즈니스 계층은 열 이름을 알아야합니다. –

+0

예를 들어, 문자열 리터럴 "Customers"로 어떤 종류의 데이터를 가져와야하는지 알려주는 것이이 질문의 요점입니다. 지금 나는 그런 것을하고 있지만 System.Type을 매개 변수로 사용하고 있습니다. 데이터 계층은 어떻게 든 "고객"을 얻는 방법을 결정합니다. 난 그냥 여기에 (문자열, 유형, 뭔가 다른) 가장 적합한 솔루션을 해결하려고 .... – Harza

관련 문제