我基本上有一个Money
值类型,它由Amount
和Currency
组成。我需要将多个Money
值映射到一个表中,该表有多个金额字段,但只有一个货币。换句话说,我有桌子:
Currency Amount1 Amount2
===============================
USD 20.00 45.00
哪个需要映射到具有2个Money值的类(逻辑上从不具有不同的货币):
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进行映射?
答案 0 :(得分:2)
这是不可能的。
如果创建Money UserType,则类型的目的是将两个基元组合成新的单一数据类型。该数据类型现在是单个原子单元。由于UserType被视为原子类型,因此映射的每个Money值都必须存在两列。 NHibernate强制实施的规则实际上在语义上是正确的。你有两个Money值。因此,您必须拥有两种货币 - 它们不能共享一种货币,因为单个货币类型具有货币和金额,现在是一个原子数据单位,不能拆分或共享。
您希望有时将货币视为变量,因此需要自己的列,并且在其他时候将其视为已修复,以便多个UserType可以共享一列。即使这是有效的,它不是基于如何定义Money,NHibernate将如何知道你想做什么?系统无法在任何给定时间知道您想要什么。您现在还需要使用Money类型保存其他数据,该类型指定了如何使用任何给定值。
底线,您的列不能映射为UserType。如果您无法更改架构,则可以执行此操作的唯一方法是将所有三列映射为普通基元,然后在应用程序代码中构造(并解构)Money类型。
结束了什么?我真的很惊讶甚至像Fowler这样的人也认为这种方法是某种“最佳实践”而没有真正考虑实际的细节。事实上,大多数数据都是一种货币由一些经常隐含或外部因素决定的行,例如原产国或企业经营的国家等等。
在您实际上甚至需要货币的情况下,您经常会有太多其他行李,这些行李来自多种货币,例如当前的汇率等,其中货币作为货币类型的一部分并不是那么有用。这是一种方便,但是对于非常不方便使用的数据而言是不可能的。大部分时间货币是固定的,通常甚至可以推断出来。因此,在典型情况下,Money类型无法接近您真正需要的 - 转换,或者它只是不必要的信息。除了少数例外,Money类型在应用程序的帮助下变成了一个dingleberry。
在你花费大量时间尝试实现某些东西之前,可能很少或没有其他原因,人们已经开始称之为“最佳实践”,问问自己,你是否甚至需要将它用于任何事情? / p>
答案 1 :(得分:1)
这是不可能的,因为当您考虑读写实体时它没有意义。
考虑Value1为USD 20
且Value2为GBP 40
的情况。你会如何坚持下去?
答案 2 :(得分: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
具有常数或至少最大数量的值,因为您需要将其映射到固定数量的列。在班级中检查这一点。
答案 3 :(得分:0)
我只是一个刚刚学习和使用NHibernate几个月的新手,但是不可能制作一个写入多列的复杂usertype(IEnhancedUserType),而一列是多余的? / p>
很难解释,但如果您将实体中的属性映射到负责读/写操作的货币列,并且您在复杂的usertype映射中多次引用同一列并关闭插入和更新,从而使它成为一个只读列,不会有用吗?我一直在考虑尝试使用这样的usertype来查看它是否有效(因为我还没有尝试过,我没有任何示例代码atm)
答案 4 :(得分: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");