首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在NHibernate组件中建模列表的最佳方法

在NHibernate组件中建模列表的最佳方法
EN

Stack Overflow用户
提问于 2021-10-12 21:58:06
回答 1查看 25关注 0票数 0

想象一下,我有一个地产网站,可以让你向不同的地产代理商查询有关某一物业的情况。不同的查询方法可能有不同的计费计算与它们相关联,而且并非所有代理都将启用每个计费模型。

代码语言:javascript
复制
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对组件(值对象)具有语义,如果组件中的每个属性都为空,则组件也将为空。

因此,通过适当的映射,您可以编写if(estateAgent.EmailEnquiryBillingModel != null),而不必检查电子邮件查询计费模型的每个单独属性,或者该模型是否有效:我们要么有模型,要么没有。这是一种简单、优雅的检查特定计费模式是否启用的方法。

当您在组件中有一组时,例如电话查询计费模式和不同的开放时间,问题就会出现。PhoneEnquiryBillingModelOpeningHours都不是实体。这些都是合法的价值对象:我们不在乎房地产经纪人是周一上午9点开门还是周一上午9点开门,只是周一上午9点开门。

因此,这似乎是在C#中表示此域模型的语义正确的方法。

然而,PhoneEnquiryBillingModel包含一个集合( ProviderOpenHours),而一个集合在NHibernate中不能为空,只能为空,这意味着ProviderOpenHours始终是非空的,即使地产代理没有有意义地启用该查询模型。(有关更多信息,请参见:https://ayende.com/blog/4685/those-are-the-rules-even-when-you-dont-like-them)。

这意味着您不能执行像if(estateAgent.PhoneEnquiryBillingModel != null)这样的简单检查,因为该对象总是非空的。

因此,对于某些计费模型,您可以执行空检查,以查看是否启用了它们,但对于其他计费模型,您必须找到另一种检查方法,这取决于这些计费模型是否包含一个集合。

实际上,您需要了解计费模型的内部结构,才能知道是否可以进行这种比较,这感觉就像您正在打破封装,并根据ORM的规则更改您的域模型。

有什么更好的方法来模拟这个吗?或者让NHibernate在没有电话号码或任何开放时间的情况下,在PhoneEnquiryBillingModel中序列化为null?

EN

回答 1

Stack Overflow用户

发布于 2021-10-13 09:07:53

因此,通过适当的映射,

可以编写if(estateAgent.EmailEnquiryBillingModel != null)

这本身并不是最好的封装。

相反,你选择:

代码语言:javascript
复制
if (estateAgent.DoesAcceptEmailEnquiries())

代码语言:javascript
复制
if (estateAgent.DoesAcceptPhoneEnquiries())

这将提供更好的封装,而不是询问EstageAgent聚合上的属性来假设EstageAgent的功能。如果您决定改变EstateAgent如何在内部存储这些信息的实现呢?你需要改变所有的客户。

EstateAgent对其基础值对象执行单独的属性检查并没有什么特别的坏处。

但是,您可以进一步在PhoneEnquiryBillingModel上实现检查器方法,甚至可能是静态的,以避免在EstateAgent中进行空检查。

PhoneEnquiryBillingModel

代码语言:javascript
复制
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;
    }
}

地产代理

代码语言:javascript
复制
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);
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69547483

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档