如何使用EF5填充扩展方法并返回IQueryable(不循环)

时间:2013-09-23 05:56:25

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

我是Entity Framework的新手。这是我的第一个使用它的项目。

我创建了一个新类,用新属性扩展我的“商家”实体,这些属性主要是计算总数。我无法找出用数据填充这些新属性的最佳方法。我正在使用breeze.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;

    }

2 个答案:

答案 0 :(得分:0)

从它的外观来看,你正在循环遍历整个表格的数据,因为有人会得到某些行。我对Breeze并不熟悉,但之前我曾与OData合作过,所以希望这个解决方案对您有用。

我建议您停止公开IQueryable<>并在内部管理查询。这样,您就可以将附加信息仅添加到要返回给客户端的记录中。这里有一些粗略的代码可以指出正确的方向:

[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;
}

using s

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

答案 1 :(得分:0)

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

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

    [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()
        };

    }