DDD(域驱动设计),如何处理实体状态更改,以及封装需要处理大量数据的业务规则 [英] DDD (Domain Driven Design), how to handle entity state changes, and encapsulate business rules that requires large amount of data to be processed

查看:432
本文介绍了DDD(域驱动设计),如何处理实体状态更改,以及封装需要处理大量数据的业务规则的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

public class Person
{
    public IList<String> SpecialBirthPlaces;
    public static readonly DateTime ImportantDate;
    public String BirthPlace {get;set;}

    public DateTime BirthDate
    {
        set
        {
            if (BirthPlace!=null && 
                value < ImportantDate && 
                SpecialBirthPlaces.Contains(BirthPlace))
            {
                BirthPlace = DataBase.GetBirthPlaceFor(BirthPlace, value);
            }
        }
    }
}

此试图在我的域模型中封装一个简单的规则。我要捕获的规则是:由于某种原因,当我们更新一个人的出生日期时(例如,原始用户输入有误),我们需要检查该人的出生地,并用来自数据库,如果它在我们的数据库中被列为特殊的出生地。

This is an attempt to encapsulate a simple rule in my domain model. The rule I'm trying to capture is: when, for some reason, we update a person's birth date (e.g. there was a mistake in the original user input) we need to check the person's birthplace and replace it with some other value from a database, if it is listed in our database as a special birthplace.

但是,我在实现它时遇到两个问题:

However, I have 2 problems implementing it:


  1. 此规则修改域实体状态(属性),我需要在用户界面中反映此更改。我的域模型是POCO。我可以将这种逻辑放入ViewModel中,但这是错误的,因为它不是UI逻辑。这是我需要捕获的重要域规则。

  1. This rule modifies domain entity state (property) and I need to reflect this change in the user interface. My domain model is POCO. I could put this logic in the ViewModel, but this is wrong because it's not UI logic. It's an important domain rule which I need to capture.

我的SpecialBirthPlaces列表非常大,我不想每次得到一个数据库中的客户。另外,当规则满足时,我需要替换出生地。正如我所说的,特殊的出生地和替代品的清单非常大,并且存储在数据库中。

My list of SpecialBirthPlaces is pretty big and I don't want to populate it every time I get a customer from database. Also, I need to get a replacement for Birthplace when the rule is satisfied. As I said the list of special birthplaces and replacements for this is very big and is stored in the DB.

如何

推荐答案

我封装此问题的方式(即修改跟踪)是与工作单位模式。我的DDD存储库与一个工作单元相关联,我可以查询该工作单元中从任何一个存储库中获取的任何实体集,以查看它们是否被修改。

The way I've encapsulated this problem, which is modification tracking, is with the Unit of Work pattern. I have my DDD repositories associated with a unit of work, and I can query the unit of work for any set of entities which I get from any of the repositories to see which are modified.

对于大型集合,它似乎是只读集。处理此问题的一种方法是,如果曾经访问过该文件,则在本地预加载和缓存该文件,然后存储库可以针对内存版本运行查询。我使用NHibernate,使用它很容易处理这种情况。如果它太大而无法存储在RAM中(例如100 MB或更多),则可能需要对存储库进行特殊情况查询,以使 SpecialBirthPlaces。在数据库上执行Contains(BirthPlace)查询(也许在存储的proc中,ha!)。您可能希望将 SpecialBirthPlaces 表示为实体的存储库,而不仅仅是大量的字符串,这将允许使用查询模式将您从繁琐的工作中解放出来。加载整个内容。

As for the large collection, it appears to be a read-only set. One way to handle this is to preload and cache this locally if it is ever accessed, then the repositories can run queries against the in-memory version. I use NHibernate, and it is easy to handle this case with it. If it is way too big to store in RAM (like 100s of MB or more), you'll probably need to special case repository queries against it, so that the SpecialBirthPlaces.Contains(BirthPlace) query is executed on the database (perhaps in a stored proc, ha!). You'd probably want to express SpecialBirthPlaces as a repository of entities, rather than just a big collection of strings, which would allow the "Query" pattern to free you from needing to load the entire thing.

经过冗长的叙述,下面是一些示例:

After this lengthy narrative, here's some example:

public class BirthPlace
{
    public String Name { get; set; }
} 

public class SpecialBirthPlace : BirthPlace
{
}

public class Person 
{
    public static readonly DateTime ImportantDate;
    public BirthPlace BirthPlace { get; set; } 

    public DateTime BirthDate 
    { 
        get; private set;
    } 

    public void CorrectBirthDate(IRepository<SpecialBirthPlace> specialBirthPlaces, DateTime date)
    {
        if (BirthPlace != null && date < ImportantDate && specialBirthPlaces.Contains(BirthPlace)) 
        { 
            BirthPlace = specialBirthPlaces.GetForDate(date); 
        }
    }
} 

有一种传递方法更正出生日期是一个更好的设计,因为它通过参数告诉您实际更正出生日期所需的条件:SpecialBirthPlace实体的存储库(即集合)和正确日期。这份明确的合同可以清楚说明域在做什么,仅通过阅读实体合同即可明确业务需求,在这种情况下,将整个集合置于实体状态即可将其隐藏。

Having a method where you pass in the corrected birth date is a better design since it tells you via the parameters what is needed to actually correct the birth date: a repository (i.e collection) of SpecialBirthPlace entities and the correct date. This explicit contract makes it clear what the domain is doing, and makes the business needs clear just by reading the entity contracts, where putting the whole collection in the state of the entity hides it.

现在我们已经将BirthPlace变成一个实体,我们可以看到可能还有更多的优化可以使域模型更加平坦。我们真的不需要专门研究 BirthPlace ,但是我们需要指出它是否特别。我们可以向对象添加一个属性(有些人讨厌域对象的属性,但是我没有,因为它使查询更容易,尤其是使用LINQ),以表明它是否特殊。然后我们就可以完全摆脱 Contains 查询:

Now that we've made BirthPlace into an entity, we can see that there may be one more optimization to make the domain model a bit flatter. We don't really need to specialize BirthPlace but we do need to indicate if it is special. We can add a property to the object (some people begrudge properties on domain objects, but I don't, since it makes queries easier, especially with LINQ) to indicate if it is special. Then we can get rid of the Contains query altogether:

public class BirthPlace
{
    public BirthPlace(String name, Boolean isSpecial = false)
    {
        Name = name;
        IsSpecial = isSpecial
    } 

    public String Name { get; private set; }
    public Boolean IsSpecial { get; private set; }
}

public class Person 
{
    public static readonly DateTime ImportantDate;
    public BirthPlace BirthPlace { get; set; } 

    public DateTime BirthDate 
    { 
        get; private set;
    } 

    public void CorrectBirthDate(IRepository<BirthPlace> birthPlaces, DateTime date)
    {
        if (BirthPlace != null && date < ImportantDate && BirthPlace.IsSpecial) 
        { 
            BirthPlace = birthPlaces.GetForDate(date); 
        }
    }
} 

这篇关于DDD(域驱动设计),如何处理实体状态更改,以及封装需要处理大量数据的业务规则的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆