MAPPAPION NHIBERNATE - USERTYPE с повторным использованием столбца?

StackOverflow https://stackoverflow.com/questions/5316172

Вопрос

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

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?

Это было полезно?

Решение

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

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

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

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

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

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

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

Другие советы

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

Рассмотрим случай, когда значение1 USD 20 и значение2 есть GBP 40. Анкет Как бы вы это упорствовали?

Как насчет того, чтобы изменить свои занятия, как это?

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

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

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

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

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");
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top