【问题标题】:How can I populate Extended Methods with EF5 and return IQueryable (without looping)如何使用 EF5 填充扩展方法并返回 IQueryable(不循环)
【发布时间】:2013-09-23 05:56:24
【问题描述】:

我是实体框架的新手。这是我第一个使用它的项目。

我创建了一个新类,它使用新属性扩展了我的“商家”实体,这些新属性主要是计算出的总数。我想不出用数据填充这些新属性的最佳方法。我正在使用微风.js 来查询 iQueryable 端点,因此我需要保持此功能完好无损。

我找到了以下解决方案,但它非常慢,因为我必须遍历每条记录。尽管我已经在微风中实现了分页,但循环仍然会命中每条记录,尽管它只返回一页。我想这就是实体框架的工作方式。我的问题是如何在不循环的情况下填充扩展属性?

这是我的代码,但它很慢。我可以消除这个循环并用一个值填充那个扩展属性吗?

    [HttpGet]
    public IQueryable<Merchant> MerchantList()
    {
        IQueryable<Merchant> items = _repo.Context.Merchants;

        foreach (var item in items)
        {

            // Total Stores
            item.TotalStores = myMethod(item.MerchantUID);

        }

        return items;

    }

【问题讨论】:

  • 您正在寻找Include 方法。
  • 非常感谢您的回复。我正在研究这个 Include 方法,它似乎用于“急切加载”相关实体,通常会导致加入。我并没有真正理解这将如何帮助我将数据加载到扩展属性中并避免循环。如果您有时间,可以详细说明一下吗?
  • “myMethod”在做什么?根据您传递给它的内容,是否可以使用 Merchant 类中的其他属性来填充 TotalStores?
  • "myMethod" 是一个查询“Stores”表以获取商店总数的函数。我还需要包括其他几个属性,尽管它们也使用更复杂的查询来查询数据库。例如,商家的一些附加扩展属性是“生命周期价值”和“剩余试用天数”。理想情况下,我想摆脱这个循环,但如果它只处理当前页面......而不是整个表格,则循环可能没问题。
  • 您需要显示myMethod 以获得正确答案。如果没有看到实现,就不可能猜出你在里面做什么以及如何改变它。

标签: c# .net entity-framework breeze iqueryable


【解决方案1】:

从外观上看,如果有人获得一些行,您正在循环遍历整个表的数据。我对Breeze 不熟悉,但我之前曾与OData 合作过,所以希望这个解决方案对你有用。

我建议您停止公开IQueryable&lt;&gt; 并在内部管理查询。这将使您能够仅将附加信息添加到您返回给客户的那些记录中。这里有一些粗略的代码可以为您指明正确的方向:

[HttpGet]
public PageResult<Merchant> MerchantList(
    ODataQueryOptions<Merchant> queryOptions)
{
    var t = new ODataValidationSettings() { MaxTop = 25 };
    var s = new ODataQuerySettings() { PageSize = 25 };
    queryOptions.Validate(t);
    IEnumerable<Merchant> results =
        (IEnumerable<Merchant>)queryOptions.ApplyTo(_repo.Context.Merchants, s);

    int skip = queryOptions.Skip == null ? 0 : queryOptions.Skip.Value;
    int take = queryOptions.Top == null ? 25 : queryOptions.Top.Value;
    long? count = Request.GetInlineCount();

    List<Merchant> pageOfResults = results.Skip(skip).Take(take).ToList();

    PageResult<Merchant> page =
        new PageResult<Merchant>(
            pageOfResults, 
            Request.GetNextPageLink(), 
            Request.GetInlineCount());

    foreach (var item in page)
    {

        // Total Stores
        item.TotalStores = myMethod(item.MerchantUID);

    }

    return page;
}

还有usings

using System.Web.Http;
using System.Web.Http.OData;
using System.Web.Http.OData.Builder;
using System.Web.Http.OData.Query;

【讨论】:

  • 谢谢。我会检查 Breeze 文档,看看这是否兼容。如果是这样,那么这似乎是一个不错的解决方案。
【解决方案2】:

感谢大家的指导。最接近的建议是关于使用 oData 的建议。我研究了急切加载,但这似乎适用于连接实体,并且这些属性无法组合。我可能会用“include”做更多的研究,以确定它是否可以用来加载单个属性,但我找不到任何关于它的文档。另一件接近的事情是投影,但 EF 不允许投影到相同的类型。我本可以投影到一个部分类,但是我会失去微风需要的元数据。如果不是微风,那将是一个非常好的解决方案。最后,虽然 Breeze 确实支持 oData,但它有太多限制(例如无法缓存),所以我想继续使用 IQueryable。

这就是我想出的。它现在只循环当前页面,但它仍然对主查询进行计数,因此 Breeze 可以在客户端上进行分页。这一切都是可能的,因为 Breeze 允许我发送获取参数,以便我可以将分页卸载到服务器。这需要大量研究,但仍不完美,但加载速度确实非常快,所以我现在必须继续前进。

    [HttpGet]
    [BreezeQueryable]
    public QueryResult MerchantList(int take, int skip)
    {

        IQueryable<Merchant> main = _repo.Context.Merchants.OrderBy(m => m.MerchantUID);

        IQueryable<Merchant> items = main.Skip(skip).Take(take);
        foreach (var item in items)
        {

            // Total LifetimeVal
            item.LifetimeVal= TotalLifetimeVal(item.MerchantUID);

            // Total Stores
            item.TotalStores = TotalStores(item.MerchantUID);

        }


        // return items;
        return new QueryResult
        {
            InlineCount = main.Count(),
            Results = items.ToList()
        };

    }

【讨论】:

  • 当不清楚循环中的方法做什么时,这对其他人来说仍然没有多大意义。当您通过 item 而不是 item.MerchantUID 时,您似乎可以利用急切加载,但是是的,谁知道呢?
  • 这对使用 Breeze JS 的人来说意义重大。它可以在不遍历整个表的情况下分配扩展属性。我还谈到了不要丢失元数据,这对 Breeze 来说非常重要。会不会更好?也许吧,但它做了我想要的。此外,没有人向我展示急切加载任意属性的示例。我了解您渴望加载其他实体(类似于加入)。你能告诉我如何急切加载任意方法,例如由一个巨大的存储过程计算的值吗?
猜你喜欢
  • 2013-05-17
  • 1970-01-01
  • 2019-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-06
  • 2015-07-10
  • 1970-01-01
相关资源
最近更新 更多