NHibernate Mapping - тип пользователя с повторным использованием столбца? - PullRequest
0 голосов
/ 15 марта 2011

У меня в основном тип значения Money, который состоит из Amount и Currency.Мне нужно отобразить несколько Money значений в таблицу, которая имеет несколько полей для суммы, но только одну валюту.Другими словами, у меня есть таблица:

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

, которую необходимо сопоставить с классом с двумя значениями денег (которые по логике никогда не могут иметь разные валюты):

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?

Ответы [ 5 ]

2 голосов
/ 15 марта 2011

Это невозможно.

Если вы создаете Money UserType, целью этого типа является объединение двух примитивов в новый единый тип данных.Этот тип данных теперь является одной атомарной единицей.Поскольку UserType считается атомарным типом, оба столбца должны присутствовать для каждого сопоставленного значения Money.Правило применения NHibernate на самом деле семантически верно.У вас есть две денежные ценности.Поэтому у вас должно быть две валюты - они не могут совместно использовать одну, потому что у одного типа денег есть Валюта и Сумма, а сейчас это один элементарный элемент данных, его нельзя разделить или разделить.

Время от времени вы хотите обрабатыватьвалюта как переменная, и, следовательно, нуждается в своем собственном столбце, а в других случаях - в фиксированном, так что несколько типов пользователя могут совместно использовать столбецДаже если бы это было верно, но это не основано на том, как определяются деньги, как бы NHibernate узнал, что вы хотите делать, когда?Система не может просто знать, что вы хотите в любой момент времени.Теперь вам также необходимо сохранить дополнительные данные с типом «Деньги», в котором указано, как предполагается использовать любое заданное значение.

В итоге ваши столбцы как таковые не могут быть отображены как пользовательский тип.Если вы не можете изменить схему, единственный способ сделать это - отобразить все три столбца как обычные примитивы, а затем создать (и удалить) тип Money в коде приложения.

А для чего кончается?Я действительно удивлен, что даже такой человек, как Фаулер, предлагает такой подход как своего рода «лучшую практику», не задумываясь о реальных деталях.Фактом является то, что большинство данных - это набор, в котором валюта определяется для ряда некоторыми часто неявными или внешними факторами, такими как страна происхождения или страна, в которой работает бизнес и т. Д. И т. Д.

Случаи, когда вы можете дажевалюта, в которой вы нуждаетесь, у вас часто бывает так много другого багажа, который исходит из нескольких валют, таких как текущие обменные курсы и т. д., что наличие валюты в качестве неотъемлемой части типа денег даже не так полезно.Это удобно, но для данных, с которыми очень неудобно работать и которые нельзя сделать иначе.Большую часть времени валюта фиксирована и обычно может быть даже выведена.Таким образом, тип Money в типичных случаях либо не может приблизиться к тому, что вам действительно нужно - конверсия, либо это просто ненужная информация.За некоторыми исключениями, тип Money становится просто чертовски привлекательным для приложения.

Прежде чем тратить много времени на попытки реализовать что-то, возможно, по малой или совсем иной причине, чем люди начали называть это «лучшей практикой», спросите себя, вам когда-нибудь понадобится использовать это длячто-нибудь? * * 1013

1 голос
/ 17 марта 2011

Как насчет изменения ваших классов, как это?

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имеет постоянное число или, по крайней мере, максимальное количество значений, потому что вам нужно сопоставить его с постоянным числом столбцов.Проверьте это в самом классе.

1 голос
/ 16 марта 2011

Это невозможно, потому что это не имеет смысла, когда вы рассматриваете чтение и запись сущностей.

Рассмотрим случай, когда Value1 равен USD 20, а Value2 равен GBP 40.Как бы вы сохранили это?

0 голосов
/ 05 сентября 2014

Я знаю, что это несколько лет спустя, но у меня есть решение.

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");
0 голосов
/ 22 марта 2011

Я просто новичок, только изучая и работаю с NHibernate уже несколько месяцев, но разве невозможно создать сложный тип пользователя (IEnhancedUserType), который пишет в несколько столбцов, тогда как один столбец будет избыточным?

Сложно объяснить, но если вы сопоставляете свойство в вашей сущности со столбцом валюты, в котором выполняются действия чтения / записи, и вы ссылаетесь на один и тот же столбец в сопоставлении сложного пользовательского типа несколько раз и отключаете вставку и обновление, таким образом, делая это только для чтения, разве это не сработает?Я думал о том, чтобы попытаться создать такой тип пользователя, чтобы увидеть, работает ли он (поскольку я еще не пробовал, у меня нет примера кода atm)

...