将同一个实体映射到不同的表
Mapping the same entity to different tables
一点领域知识
我正在编写一个 POS(销售点)软件,它允许支付货物或退款。
付款或退款时,需要指定使用哪种汇款方式:现金、EFT(~=信用卡)、会员卡、代金券等
这些汇款方式是一组有限且已知的值(一种枚举)。
棘手的部分是我需要能够在 POS 终端上存储这些方式的自定义子集以用于支付和退款(两组可能不同)。
例如:
- 可用的支付方式:现金、电子转帐、会员卡、代金券
- 可用退款方式:现金、代金券
当前实施状态
我选择实施汇款方式的概念如下:
public abstract class MoneyTransferMean : AggregateRoot
{
public static readonly MoneyTransferMean Cash = new CashMoneyTransferMean();
public static readonly MoneyTransferMean EFT = new EFTMoneyTransferMean();
// and so on...
//abstract method
public class CashMoneyTransferMean : MoneyTransferMean
{
//impl of abstract method
}
public class EFTMoneyTransferMean : MoneyTransferMean
{
//impl of abstract method
}
//and so on...
}
它不是 "plain enum" 的原因是这些 class 中存在一些行为。我还必须声明内部 classes public(而不是私有的)以便在 FluentNHibernate 映射中引用它们(见下文)。
如何使用
付款方式和退款方式总是作为一组存储或检索 in/from 数据库。它们实际上是两个不同的集合,尽管两个集合中的某些值可能相同。
用例1:定义一组新的payment/refund意味着
- 删除所有现有的payment/refund手段
- 插入新的
用例 2:检索所有 payment/refund 手段
- 获取所有存储的payment/refund手段的集合
问题
我在持久性方面坚持我当前的设计。我正在使用 NHibernate(使用 FluentNHibernate 来声明 class 映射),但我找不到将其映射到某些有效数据库模式的方法。
我发现可以使用 entity-name 多次映射 class 但是我不确定是否可以使用 subclasses.
我还没准备好做的是改变 MoneyTransferMean public API 以便能够持久化它(例如添加 bool isRefund
来区分两者) .但是添加一些私有鉴别器字段是可以的。
我当前的映射:
public sealed class MoneyTransferMeanMap : ClassMap<MoneyTransferMean>
{
public MoneyTransferMeanMap()
{
Id(Entity.Expressions<MoneyTransferMean>.Id);
DiscriminateSubClassesOnColumn("Type")
.Not.Nullable();
}
}
public sealed class CashMoneyTransferMeanMap : SubclassMap<MoneyTransferMean.CashMoneyTransferMean>
{
public CashMoneyTransferMeanMap()
{
DiscriminatorValue("Cash");
}
}
public sealed class EFTMoneyTransferMeanMap : SubclassMap<MoneyTransferMean.EFTMoneyTransferMean>
{
public EFTMoneyTransferMeanMap()
{
DiscriminatorValue("EFT");
}
}
//and so on...
这个映射编译但是它只产生 1 table 并且在查询这个 table.
时我无法区分 payment/refund
我试图用不同的 table 和实体名称声明两个引用 MoneyTransferMean
的映射,但这导致我出现异常 Duplicate class/entity mapping MoneyTransferMean+CashMoneyTransferMean
.
我也尝试复制 subclass 映射,但我无法指定 "parent mapping",这导致我遇到与上述相同的异常。
问题
是否存在持久化我当前域实体的解决方案?
如果不是,我需要对我的实体执行什么最小的重构才能使它们与 NHibnernate 保持一致table?
你为什么不创建一个单一的实体 MoneyTransferMean,具有所有公共属性(字段)并添加 2 个额外的字段(布尔值)以确定 MoneyTransferMean 是否是付款或退款,或两者兼而有之????坚持不坚持。
也可以使用带有 Id (PK) 的额外实体来完成,添加相同的额外字段,与 MoneyTransferMean 的关系将是 1:1。丑陋,我知道,但它应该工作。
我赞成并补充@DEVX75 建议的内容,因为您的交易类型本质上描述了相同的概念,尽管一个是 +ve 而另一个是 -ve。不过,我可能只添加一个布尔字段,并有单独的记录来区分退款和付款。
假设您有一个 UID 并且没有使用手段标签名称作为 ID,您可以允许手段名称重复,并包括两个现金条目,例如:
UID, Label, IsRefund
1, Cash, false
2, Cash, true
3, Voucher, false
4, Voucher, true
那么你可以轻松得到以下内容:
Transaction Type = MoneyTransferMean.IsRefund? "Refund" : "Payment"
Transaction Value = MoneyTransferMean.IsRefund? MoneyTransfer.amount * -1 : MoneyTransfer.amount
这样一来,如果您在交易中引用了 MoneyTransferMean.UID = 2,您就知道这是现金退款,而不是知道这是一种可以是现金退款或现金支付。
最后,我决定通过将实体 MoneyTransferMean
复制为两个实体 PaymentMean
和 RefundMean
.
来解决问题
虽然在实现上相似,但这两个实体之间的区别在业务中是有意义的,对我来说是最不糟糕的解决方案。
一点领域知识
我正在编写一个 POS(销售点)软件,它允许支付货物或退款。 付款或退款时,需要指定使用哪种汇款方式:现金、EFT(~=信用卡)、会员卡、代金券等
这些汇款方式是一组有限且已知的值(一种枚举)。
棘手的部分是我需要能够在 POS 终端上存储这些方式的自定义子集以用于支付和退款(两组可能不同)。
例如:
- 可用的支付方式:现金、电子转帐、会员卡、代金券
- 可用退款方式:现金、代金券
当前实施状态
我选择实施汇款方式的概念如下:
public abstract class MoneyTransferMean : AggregateRoot
{
public static readonly MoneyTransferMean Cash = new CashMoneyTransferMean();
public static readonly MoneyTransferMean EFT = new EFTMoneyTransferMean();
// and so on...
//abstract method
public class CashMoneyTransferMean : MoneyTransferMean
{
//impl of abstract method
}
public class EFTMoneyTransferMean : MoneyTransferMean
{
//impl of abstract method
}
//and so on...
}
它不是 "plain enum" 的原因是这些 class 中存在一些行为。我还必须声明内部 classes public(而不是私有的)以便在 FluentNHibernate 映射中引用它们(见下文)。
如何使用
付款方式和退款方式总是作为一组存储或检索 in/from 数据库。它们实际上是两个不同的集合,尽管两个集合中的某些值可能相同。
用例1:定义一组新的payment/refund意味着
- 删除所有现有的payment/refund手段
- 插入新的
用例 2:检索所有 payment/refund 手段
- 获取所有存储的payment/refund手段的集合
问题
我在持久性方面坚持我当前的设计。我正在使用 NHibernate(使用 FluentNHibernate 来声明 class 映射),但我找不到将其映射到某些有效数据库模式的方法。
我发现可以使用 entity-name 多次映射 class 但是我不确定是否可以使用 subclasses.
我还没准备好做的是改变 MoneyTransferMean public API 以便能够持久化它(例如添加 bool isRefund
来区分两者) .但是添加一些私有鉴别器字段是可以的。
我当前的映射:
public sealed class MoneyTransferMeanMap : ClassMap<MoneyTransferMean>
{
public MoneyTransferMeanMap()
{
Id(Entity.Expressions<MoneyTransferMean>.Id);
DiscriminateSubClassesOnColumn("Type")
.Not.Nullable();
}
}
public sealed class CashMoneyTransferMeanMap : SubclassMap<MoneyTransferMean.CashMoneyTransferMean>
{
public CashMoneyTransferMeanMap()
{
DiscriminatorValue("Cash");
}
}
public sealed class EFTMoneyTransferMeanMap : SubclassMap<MoneyTransferMean.EFTMoneyTransferMean>
{
public EFTMoneyTransferMeanMap()
{
DiscriminatorValue("EFT");
}
}
//and so on...
这个映射编译但是它只产生 1 table 并且在查询这个 table.
时我无法区分 payment/refund我试图用不同的 table 和实体名称声明两个引用 MoneyTransferMean
的映射,但这导致我出现异常 Duplicate class/entity mapping MoneyTransferMean+CashMoneyTransferMean
.
我也尝试复制 subclass 映射,但我无法指定 "parent mapping",这导致我遇到与上述相同的异常。
问题
是否存在持久化我当前域实体的解决方案?
如果不是,我需要对我的实体执行什么最小的重构才能使它们与 NHibnernate 保持一致table?
你为什么不创建一个单一的实体 MoneyTransferMean,具有所有公共属性(字段)并添加 2 个额外的字段(布尔值)以确定 MoneyTransferMean 是否是付款或退款,或两者兼而有之????坚持不坚持。
也可以使用带有 Id (PK) 的额外实体来完成,添加相同的额外字段,与 MoneyTransferMean 的关系将是 1:1。丑陋,我知道,但它应该工作。
我赞成并补充@DEVX75 建议的内容,因为您的交易类型本质上描述了相同的概念,尽管一个是 +ve 而另一个是 -ve。不过,我可能只添加一个布尔字段,并有单独的记录来区分退款和付款。
假设您有一个 UID 并且没有使用手段标签名称作为 ID,您可以允许手段名称重复,并包括两个现金条目,例如:
UID, Label, IsRefund
1, Cash, false
2, Cash, true
3, Voucher, false
4, Voucher, true
那么你可以轻松得到以下内容:
Transaction Type = MoneyTransferMean.IsRefund? "Refund" : "Payment"
Transaction Value = MoneyTransferMean.IsRefund? MoneyTransfer.amount * -1 : MoneyTransfer.amount
这样一来,如果您在交易中引用了 MoneyTransferMean.UID = 2,您就知道这是现金退款,而不是知道这是一种可以是现金退款或现金支付。
最后,我决定通过将实体 MoneyTransferMean
复制为两个实体 PaymentMean
和 RefundMean
.
虽然在实现上相似,但这两个实体之间的区别在业务中是有意义的,对我来说是最不糟糕的解决方案。