2011-03-15 3 views
0

기본적으로 AmountCurrency으로 구성된 값 유형이 Money입니다. 금액이 여러 필드지만 하나의 통화 만있는 테이블에 여러 Money 값을 매핑해야합니다.NHibernate 매핑 - 재사용되는 컬럼을 가진 UserType?

Currency  Amount1 Amount2 
=============================== 
USD   20.00  45.00 

(다른 통화가없는 논리적 않을 수 있습니다) 2 개 돈 값으로 클래스에 매핑 할 필요가있다 :

class Record 
{ 
    public Money Value1 { get; set; } 
    public Money Value2 { get; set; } 
} 

struct Money 
{ 
    public decimal Amount { get; set; } 
    public string Currency { get;set; } 
} 

(예 조금있다 주문 즉, 나는 테이블이 단순화)

테이블 스키마는 변경할 수 없습니다. 필요한 경우 IUserType을 구현하게되어 기쁩니다. 그러나 두 값 모두 Currency 열에 액세스하는 방법을 알 수는 없습니다.

어떻게 NHibernate를 사용하여 매핑합니까?

답변

2

불가능합니다.

Money 사용자 유형을 만드는 경우 유형의 목적은 두 개의 프리미티브를 새로운 단일 데이터 유형으로 결합하는 것입니다. 이 데이터 유형은 이제 하나의 원자 단위입니다. UserType은 원자 유형으로 간주되므로 매핑 된 각 Money 값에 대해 두 열이 모두 있어야합니다. NHibernate가 강제하는 규칙은 실제로 의미 상으로 정확합니다. 두 개의 Money 값이 있습니다. 따라서 두 개의 통화가 있어야합니다. 하나의 Money 유형이 통화 및 금액을 가지며 현재 하나의 원자 단위로되어 있기 때문에 두 통화를 공유 할 수 없습니다. 분할되거나 공유 될 수 없습니다.

때때로 통화를 변수로 처리해야하므로 여러 개의 UserTypes가 모두 열을 공유 할 수 있도록 자체 열과 고정 된 시간이 필요합니다. 그것이 돈이 정의되는 방법에 기반하지 않는 것이 유효하더라도, NHibernate는 당신이 뭘하고 싶었는지 어떻게 알 수 있을까요? 시스템은 주어진 시간에 원하는 것을 알 수 없습니다. 이제 특정 값의 사용 방법을 지정하는 Money 유형으로 추가 데이터를 저장해야합니다.

하단에는 사용자가 지정한대로 열을 UserType으로 매핑 할 수 없습니다. 스키마를 변경할 수 없다면이 세 가지 열을 모두 기본 프리미티브로 매핑 한 다음 응용 프로그램 코드에서 Money 형식을 생성 (및 해체)해야합니다.

그리고 끝나는 부분은 무엇입니까? 파울러 (Fowler)와 같은 사람조차도 실제적인 세부 사항을 고려하지 않고이 접근법을 일종의 "모범 사례 (best practice)"라고 제안하는 것이 정말 놀랍습니다. 사실 대부분의 데이터는 통화가 비즈니스가 운영되는 원산지 또는 국가와 같이 암시 적 또는 외적 요인에 의해 행에 대해 지시되는 집합입니다.

실제로 통화가 필요할 수도있는 경우 당신은 종종 현재 환율과 같은 여러 통화에서 발생하는 많은 다른 수하물을 가지고 있습니다. 통화 유형을 돈 유형의 일부로 간주하는 것은 도움이되지 않습니다. 편의성은 있지만 작업하기가 매우 불편하고 달리 작성할 수없는 데이터의 경우 유용합니다. 대부분의 시간 통화는 고정되어 있으며 일반적으로 유추 할 수도 있습니다. 따라서 일반적인 경우의 Money 유형 중 하나는 전환 또는 단순히 불필요한 정보 일뿐입니다. 몇 가지 예외를 제외하면 Money 유형은 응용 프로그램의 엉덩이에 단지 dingleberry됩니다.

여하튼 사람들이이 "모범 사례"라고 부르기 시작한 것보다 거의 또는 전혀 다른 이유로 당신이 무언가를 구현하려고 많은 시간을 소비하기 전에 무엇을 위해 그것을 사용해야 할 필요가 있는지 자문 해보십시오.

+1

+1, 나는 돈 값 유형의 유용성에 당신과 함께 동의하지만. – driis

1

엔티티 엔티티를 읽고 쓰는 경우에는 이라고 생각하면 이해가되지 않기 때문에 불가능합니다.

Value1이 USD 20이고 Value2가 GBP 40 인 경우를 고려하십시오. 어떻게 그걸 유지하겠습니까?

+0

나는 그것을 이해하지만, 내 논리는 통화가 동일한 기록에서 동일해야한다고 규정합니다. 여러 통화 열을 포함하도록 스키마를 변경할 수 있다면 나는 적절하게 할 것이다. – driis

+0

@driis : 그러면 도메인을 변경해야합니다. 또한, NHibernate는 그 제약에 대해 알 수 없다. –

1

이렇게 수업을 변경하면 어떨까요?

class Record 
{ 
    public MoneyCollection Money { get; set; } 
} 

class MoneyCollection 
{ 
    public MoneyCollection(string currency, params decimal[] amount1) { /*...*/ } 
    public decimal[] Amount { get; private set; } 
    public string Currency { get; private set; } 
    public Money[] Money 
    { 
     get 
     { 
     return Amount.Select(x => new Money(Currency, x)).ToArray(); 
     } 
    } 
} 

class Money 
{ 
    public Money(decimal amount, string currency) { /* ... */ } 
    public decimal Amount { get; private set; } 
    public string Currency { get; private set; } 
} 

이제는 MoneyCollection에 대한 사용자 유형을 쓸 수 있습니다.

참고 : 일정한 수의 열에 매핑해야하기 때문에 MoneyCollection에는 상수 또는 최대 값 수가 있어야합니다. 이것을 클래스 자체에서 확인하십시오.

0

나는 단지 몇 달 동안 NHibernate에 대해 배우고 작업하고있는 초보자 일 뿐이지 만 하나의 열이 중복되는 반면 여러 열에 쓰는 복잡한 사용자 유형 (IEnhancedUserType)을 만드는 것은 불가능합니까?

설명하기 어렵지만 엔티티의 속성을 읽기/쓰기 작업을 처리하는 통화 열로 매핑하고 복잡한 사용자 유형 매핑 내에서 동일한 열을 여러 번 참조하고 삽입 및 업데이트를 끄면, 따라서 그것을 읽기 전용 컬럼으로 만드는 것은 효과가 없을까요? 나는 그것이 작동하는지 알기 위해 이와 같은 사용자 유형을 만들려고 노력했다. (아직 시도하지 않았기 때문에 예제 코드가 없다.)

0

나는 그것이 몇 년 늦었다는 것을 알고있다. -하지만 해결책이 있어요.

private decimal _subTotal; 
private decimal _shipping; 
private CurrencyIsoCode _currency; 

public virtual Money SubTotal 
{ 
    get { return new Money(_subTotal, _currency); } 
    set 
    { 
     _subTotal = value.Amount; 
     _currency = value.CurrencyCode; 
    } 
} 

public virtual Money Shipping 
{ 
    get { return new Money(_shipping, _currency); } 
    set 
    { 
     _shipping = value.Amount; 
     _currency = value.CurrencyCode; 
    } 
} 

매핑 :

Map(Reveal.Member<Basket>("_subTotal")).Column("SubTotal"); 
Map(Reveal.Member<Basket>("_shipping")).Column("Shipping"); 
Map(Reveal.Member<Basket>("_currency")).Column("Currency");