【问题标题】:How should I return custom result sets from repository?我应该如何从存储库返回自定义结果集?
【发布时间】:2014-01-31 04:00:08
【问题描述】:

我有名为 Product 和 Orders 的商业模式,如下所示:

public class Product
{
    public int ProductId {get; set;}
    public string Name {get; set;}
}

public class Order
{
    public int OrderId{get; set;}
    public int ProductId {get; set;}
    ...
}

在我的存储库层中,我想返回一个产品集合,其中包含针对每个产品的订单计数,但我无法找出正确的方法或返回自定义结果集:

public ?? GetProductsWithOrderCount()
{
    var resultSet = from p in Products
              join o in Orders on p.ProductId equals o.ProductId into grp
              select new
              {
                   Product = p, 
                   OrdersCount = grp.Count(); // Does not work, just for demonstration
              };
    return resultSet;
}

现在我知道我可以使用IEnumerable<object> 作为返回类型,但是我必须将结果集转换到我在服务层中使用它的位置。

另一种选择是我可以创建另一个模型并返回 IEnumerable<ProductWithOrderCount> 但这会添加不代表我的系统的不必要模型:

public class ProductWithOrderCount
{
    public Product Product {get; set;}
    public int OrdersCount {get; set;}
}

还有其他方法吗?

【问题讨论】:

  • 您必须创建包含 getter setter 这两个模型的视图模型
  • 我相信,问题在于您正在使用存储库来返回摘要/聚合数据。该存储库用于返回 聚合根 - 顶级实体,然后您将在逻辑层中编写查询以生成计数。
  • View Models 应该在 UI 层,对吧?这是在存储库层中。
  • @Keith 问题在于我所有的存储库都返回IEnumerables,这使得在服务层中查询数据的成本非常高。

标签: c# asp.net-mvc entity-framework architecture repository-pattern


【解决方案1】:

这就是 DTO(数据传输对象)的用途,是的,添加一个类来处理响应是完全合理的。您已经拥有的类ProductWithOrderCount 很好,只是我会在类名称的末尾添加DTO 以更清楚地表明这是一个旨在容纳自定义数据库结果的类。

【讨论】:

    【解决方案2】:

    您的存储库层是隐藏所有存储抽象的层。不要让它们泄漏到您的业务逻辑中,即。业务代码应该不能直接向存储发出额外的查询,即使它看起来很方便。同样适用于例外。如果您使用某种延迟加载,您就有可能在业务层中获得数据库级别的异常,或者在演示中出现更糟的情况。因此,您需要完全加载您的对象树并在那里处理所有 DB/连接异常,或者将它们包装到 StorageException 之类的东西中并抛出它们。

    如果您的业务逻辑需要 ProductsWithOrders,那就这样吧 - 您需要创建另一个类 ProductsWithOrders。你可以喜欢并创建像 Ledger 这样的模板类,以后可以像 new Ledger 一样使用它,但我个人会等到你有另一对类来证明它的合理性。

    【讨论】:

      【解决方案3】:

      我的应用中有一个非常相似的要求。这是用于分页,因为我返回的对象集合可能是 10、15 或 20 个项目,但计数将是数百个的完整数据库计数。在你的情况下,虽然返回的数字和收集计数是相同的。

      我最终创建了一个通用返回类型,它看起来像这样,但是您可以随意调用该类,例如 EnumerableWithCount

      public class PagedList<T>
      {
          public int TotalCount { get; set; }
          public IEnumerable<T> Items { get; set; }
      
          public PagedList(IEnumerable<T> collection, int totalCount)
          {
              Items = collection;
              TotalCount = totalCount;
          }
      }
      

      如果我正确地掌握了您要查找的内容,您将有一个看起来像这样的返回类型。

      IEnumerable&lt;EnumerableWithCount&lt;Product&gt;&gt;

      【讨论】:

        【解决方案4】:
                  from p in Products
                  select new ProductWithOrderCount()
                  {
                       Product = p, 
                       OrdersCount = p.Orders.Count(),
                  };
        

        移除连接并使用导航属性。

        特殊的 DTO 类是正确的做法。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-03-27
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多