【问题标题】:EF, Repositories and crossing aggregate boundariesEF、存储库和跨越聚合边界
【发布时间】:2014-09-19 17:20:05
【问题描述】:

我的域中有两个聚合根,因此有两个存储库。为了举例,我们将它们称为 BookRepository 和 AuthorRepository。

我正在设计一个 MVC 应用程序,一个页面必须显示一个包含作者列表的表格,每一行都显示作者的个人详细信息。每行的末尾都有一个小按钮,单击该按钮可展开该行并显示一个子表,详细说明作者已出版的书籍。

页面加载时,会执行一些 ajax 从 API 控制器检索作者详细信息并在表中显示数据。 Author 对象中的每个属性几乎都直接映射到一列,但有一个例外,这就是我遇到问题的地方。当且仅当作者没有出版书籍时,我希望禁用每行末尾的按钮。这意味着每个作者记录都必须返回一个布尔值,指示他们是否有任何已出版的书籍。

我的书库有几个这样的方法:

public IEnumerable<Book> GetBooksForAuthor(int authorId);

public bool AnyBooksForAuthor(int authorId);

我的 Book 类有一个名为 AuthorId 的属性,所以我可以通过调用来检索一本书的作者

authorRepository.GetById(book.AuthorId);

我的问题是,为了为上述表格创建一行,我需要像这样创建它:

IEnumerable<Author> authors = authorRepository.GetAll();
foreach (Author author in authors)
{
    yield return new AuthorTableRow
    {
        Name = author.Name,
        Age = author.Age,
        Location = author.PlaceOfResidence.Name,
        HasBooks = this.bookRepository.AnyBooksForAuthor(author.Id)
    };
}

上面的代码看起来是正确的,但是在为每个作者调用 this.bookRepository.AnyBooksForAuthor(author.Id) 时会有相当大的性能损失,因为它每次都会执行一次数据库调用。

理想情况下,我想我想要一个 AuthorTableRowRepository 可以执行以下操作:

public IEnumerable<AuthorTableRow> GetAll()
{
    return from a in this.dbContext.Authors
           select new AuthorTableRow
           {
               Name = a.Name,
               Age = a.Age,
               Location a.PlaceOfResidence.Name
               HasBooks = a.Books.Any()
           });
}

出于以下原因,我犹豫是否要执行此操作:

  • AuthorTableRowRepository 是 AuthorTableRows 的存储库,但 AuthorTable 行不是域对象,也不是聚合根,因此不应有自己的存储库。
  • 由于 Author 和 Book 都是聚合根,我从 Author 实体中删除了“Books”属性,因为我希望通过 BookRepository 检索书籍的唯一方法。这使得 HasBooks = a.Books.Any() 不可能。我不确定我是否在这里强加我自己被误导的最佳实践。通过 AuthorRepository 获取作者然后通过其 Books 属性来获取 Books 似乎是错误的,反之亦然,通过 Book 对象上的属性获取作者。我想,跨越聚合根边界将是我所说的方式?

其他人会如何解决这个问题?我的担心是没有根据的吗?我最关心的是第一种方法对性能的影响(应该是什么),但我想坚持使用存储库模式和 DDD 的最佳实践。

【问题讨论】:

  • 为什么要投反对票...?请解释一下,以免我下次出错?

标签: entity-framework repository domain-driven-design aggregateroot


【解决方案1】:

我会坚持第一种方法,但尝试优化 bookrepository 方法中的内容。例如,您可以一次性加载所有信息,并使用内存查找来加快速度。像这样,您需要 2 个查询,而不是每个作者 1 个。

【讨论】:

  • 如何优化bookrepository方法?这是一个非常直接的 .Any() 对数据库的查询,我不确定我还能做些什么来优化它?
  • 好吧,如果 bookrepository 有一个按作者分类的书籍数量的内存列表,你只需要在循环之前初始化列表,就像这样; this.bookRepository.LoadBooksByAuthor(); IEnumerable&lt;Author&gt; authors = authorRepository.GetAll(); foreach (Author author in authors) { yield return new AuthorTableRow { Name = author.Name, Age = author.Age, Location = author.PlaceOfResidence.Name, HasBooks = this.bookRepository.AnyBooksForAuthor(author.Id) // this call does not go to the database, but is just an in-memory lookup }; }
  • 如果 bookRepository 有数百万本书要加载,那真的更好吗? bookRepository 也无法加载表的子集,因为在执行作者查询之前它不知道您需要哪些书籍的信息?
  • 确实,我不会加载所有书籍......只加载作者的书籍总数。此内存列表将按作者记录...
【解决方案2】:

我最终解决这个问题的方法是从数据库中的视图创建一个实体。我将实体命名为“AuthorSummary”,并创建了一个不包含任何 Add() 方法的 AuthorSummaryRepository,仅包含检索方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-15
    • 1970-01-01
    • 2021-04-16
    • 1970-01-01
    • 1970-01-01
    • 2018-09-11
    • 1970-01-01
    • 2014-06-27
    相关资源
    最近更新 更多