nhibernate - 在 NHibernate 中的组件内建模列表的最佳方法
问题描述
想象一下,我有一个房地产网站,可让您向不同的房地产经纪人询问有关给定财产的信息。不同的查询方法可能具有与之关联的不同计费计算,并且并非所有代理都会启用每种计费模型。
public class EmailEnquiryBillingModel : ValueObject
{
public string EmailAddress { get; set; }
public decimal CostPerEnquiry { get; set; }
}
public enum DayOfWeek
{
Monday,
Tuseday,
// etc.
}
public class OpeningHours : ValueObject
{
public DateTime OpeningTime { get; set; }
public DateTime ClosingTime { get; set;}
}
public class PhoneEnquiryBillingModel : ValueObject
{
public PhoneEnquiryBillingModel()
{
OpeningHours = new Dictionary<DayOfWeek, OpeningHours>();
}
public int PhoneNumber { get; set; }
public IDictionary<DayOfWeek, OpeningHours> OpeningHours { get; set; }
}
public class EstateAgent : Entity
{
public string Name { get; set; }
public EmailEnquiryBillingModel EmailEnquiryBillingModel { get; set; }
public PhoneEnquiryBillingModel PhoneEnquiryBillingModel { get; set; }
}
NHibernate 具有组件(值对象)的语义,如果组件中的每个属性都为 null,则该组件也将为 null。
因此,通过适当的映射,您可以编写if(estateAgent.EmailEnquiryBillingModel != null)
而不需要检查电子邮件查询计费模型的每个单独属性,或者该模型是否有效:我们要么有模型,要么没有。这是一种检查是否启用了特定计费模型的简单、优雅的方法。
当您在一个组件中有一个集合时,问题就出现了,例如电话查询计费模型和各种开放时间。thePhoneEnquiryBillingModel
和 the都不OpeningHours
是实体。这些是合法的价值对象:我们不关心房地产经纪人是在周一上午 9 点还是从周一上午 9 点开始营业,只关心它在周一上午 9 点开始营业。
因此,这感觉像是在 C# 中表示此域模型的语义正确方式。
然而,PhoneEnquiryBillingModel
包含一个集合 (of ProviderOpenHours
),并且集合在 NHibernate 中不能为空,只能为空,这意味着ProviderOpenHours
即使房地产经纪人没有有意义地启用该查询模型,它也将始终为非空。(有关更多信息,请参阅:https ://ayende.com/blog/4685/those-are-the-rules-even-when-you-dont-like-them )。
这意味着您不能像 一样进行简单的检查if(estateAgent.PhoneEnquiryBillingModel != null)
,因为该对象始终不为空。
因此,对于某些计费模型,您可以进行空值检查以查看它们是否已启用,但对于其他计费模型,您必须找到另一种检查方式,具体取决于这些计费模型是否包含一组。
实际上,您需要了解计费模型的内部结构才能知道是否可以进行这种比较,这感觉就像您正在打破封装并根据 ORM 的规则更改域模型。
有没有更好的建模方法?PhoneEnquiryBillingModel
或者,如果 NHibernate没有电话号码或任何营业时间,是否可以让 NHibernate 在 as null 中序列化?
解决方案
因此,通过适当的映射,您可以编写 if(estateAgent.EmailEnquiryBillingModel != null)
这本身并不是最好的封装。
相反,你去:
if (estateAgent.DoesAcceptEmailEnquiries())
和
if (estateAgent.DoesAcceptPhoneEnquiries())
与询问 EstageAgent 聚合上的属性以对 EstateAgent 的能力进行假设相比,这将提供更好的封装。如果您决定更改 EstateAgent 在内部存储此信息的方式的实现,该怎么办?您需要更改所有客户端。
EstateAgent 对其基础价值对象执行单个属性检查并没有什么特别糟糕的地方。
但是,您可以更进一步,在 PhoneEnquiryBillingModel 上实现一个检查器方法,甚至可能是静态的,以避免在 EstateAgent 中进行空检查。
电话查询计费模式
public class PhoneEnquiryBillingModel : ValueObject
{
public PhoneEnquiryBillingModel()
{
OpeningHours = new Dictionary<DayOfWeek, OpeningHours>();
}
public int PhoneNumber { get; set; }
public IDictionary<DayOfWeek, OpeningHours> OpeningHours { get; set; }
public static bool DoesAcceptEnquiries(PhoneEnquiryBillingModel phone)
{
if (phone == null) return false;
if (phone.OpeningHours.Count == 0) return false;
return true;
}
}
地产代理
public class EstateAgent : Entity
{
public string Name { get; set; }
public EmailEnquiryBillingModel _emailEnquiryBillingModel { get; set; }
public PhoneEnquiryBillingModel _phoneEnquiryBillingModel { get; set; }
public bool DoesAcceptPhoneEnquiries()
{
return PhoneEnquiryBillingModel.DoesAcceptEnquiries(
_phoneEnquiryBillingModel);
}
}
推荐阅读
- javascript - 如何在 Node.js 中使用 MongoDB 的填充方法?
- forms - 如何从 YouTube 视频中获取音频并将其放入基于 Visual Basic 表单的音乐播放器中?
- go - 从 Go 中的通道接收值
- visual-studio - 处理丢失 MSVCP140D.dll 的 Visual Studio 设置
- azure - PackageReference 的 Azure 部署问题
- webforms - ReportViewer 打印一页字母大小,但是当我打印时它是两页
- python - DataFrame、apply、lambda、列表理解
- regex - 正则表达式在字符串行中多次出现
- .net - 如何设置 .Net Core 数据库连接以使用在 Docker 容器中运行的 MS SQL Server?
- css - CSS 特定性与 CSS 模块