繁体   English   中英

域驱动设计和聚合

[英]Domain Driven Design and Aggregates

我正在构建一个小的Recipe Organizer MVC项目,首先使用EntityFramework Code和Sql Server Compact版本,以了解有关DDD和Repository模式的更多信息。

以下是我的一些域实体,我已针对此问题对其进行了简化。

public class Recipe {

    public int Id { get; set; }

    [Required]
    public string Name { get; set; }

    /// <summary>
    /// Represents a common meal type of “Breakfast, Lunch or Dinner” 
    /// or type of course “Appetisers, Soups, Salads, Fish, Poultry & Game, Meat, Side dishes, Desserts, Miscellaneous", etc.
    /// (for scope I am not considering brunch or supper or any other type) 
    /// </summary>
    [Required]
    public Course Course { get; set; }


    public virtual ICollection<Ingredient> Ingredients { get; set; }
}

public class Ingredient {
    public int Id { get; set; }
    [Required]
    public string Name { get; set; }
}

public class Course {
    public int Id { get; set; }
    [Required]
    public string Name { get; set; }
}

在我看来,对于这个项目的范围,我会说Recipe是一个聚合根和成分和课程是Recipe的聚合。

如果我采用此示例并使用MVC脚手架为我提供存储库模式的示例实现,我将获得以下接口和实现该接口的EFRecipeRepository类,并具有对EF DB上下文的引用。

public interface IRecipeRepository
{
    IQueryable<Recipe> All { get; }
    IQueryable<Recipe> AllIncluding(params Expression<Func<Recipe, object>>[] includeProperties);
    Recipe Find(int id);
    void InsertOrUpdate(Recipe recipe);
    void Delete(int id);
    void Save();
}

遵循此指导:

在存储库模式的上下文中,聚合根是客户端代码从存储库加载的唯一对象。

存储库封装了对子对象的访问 - 从调用者的角度来看,它会自动加载它们,无论是在加载根目录还是实际需要它们时(如延迟加载)。

我希望在此界面中添加更多内容,以便通过食谱获得成分或课程。

我遇到的问题是我想在我的视图中添加一些仅涉及成分或课程的功能,例如:所有不同类型课程的导航(不仅仅是与食谱相关的课程)和自动完成列表成分。

在我的项目范围内,配方不存在于食谱之外,因此它应该是食谱的聚合似乎是可行的。 然而,看起来它应该是一个聚合根本身,因为它本身如何存在?

我正在努力想象这一切应该如何运作,如果我想获得每个成分的清单意味着我首先必须使用食谱库来加载所有的食谱以便找到所有的成分?

课程有类似的问题,除了它被用作分类食谱的方式,因此也可以存在于该边界之外。

我缺少一些概念吗? 也许是一种创建用于此类表示层要求的服务的方法? 有没有人对如何做到这一点有任何意见? 或者更好的建议? 谢谢

另外,这是一个小项目,DDD可能不是最好的方法,但我确实发现存储库模式对于我的Domain模型中的持久性无知非常有用。

谢谢

我正在努力想象这一切应该如何运作,如果我想获得每个成分的清单意味着我首先必须使用食谱库来加载所有的食谱以便找到所有的成分?

如果您只需要一个自动完成的不同成分名称列表,我确实只提供一个从数据库中提取必要报告的服务。 我完全可以使用聚合中的报告,因为它们只是 - 报告。 您不应该让服务从聚合内部返回可用实体(即不返回Ingredient []),因为这会打开调用者的聚合边界。 只需返回一个字符串[]或类似字符串。

然后,我会考虑课程和成分聚合根源,除了最琐碎的应用程序。 成分可以没有配方吗? 绝对! “糖”#1(属于食谱#1)是否与“糖”#2(属于食谱#2)不同? 我不这么认为。 有糖。 还有一些使用糖的食谱。 制作成分聚合根源很有意义。 例如,您可以通过成分轻松浏览您的食谱。

同样适用于课程,这是一个绝对有意义的概念。

一个不应该是聚合根的概念的一个很好的例子是一个订单行(也就是说,“3件Foobar电视每件700美元”)。 如果没有订单,订单行就毫无意义。 但即使在这种情况下,在订单行上生成报告的服务也是有意义的(在理论上)并且是合法的IMO。 例如,人们可能想知道通常一起购买多少Foobar电视,以便推出新的Foobar TV 3-pack(是的,无论如何......)。 这将再次意味着在数据库中搜索通常无法直接访问的数据。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM