简体   繁体   English

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

[英]How can I populate Extended Methods with EF5 and return IQueryable (without looping)

I'm new to Entity Framework. 我是实体框架的新手。 This is my first project using it. 这是我第一个使用它的项目。

I've created a new class that extends my "merchant" entity with new properties, which are mostly calculated totals. 我创建了一个新类,将新的属性扩展为“商人”实体,这些属性大多是计算得出的总数。 I could not figure out the best way to populate those new properties with data. 我想不出用数据填充这些新属性的最佳方法。 I am using breeze.js to query an iQueryable endpoint so I need to keep this functionality intact. 我正在使用breeze.js来查询iQueryable端点,因此我需要保持此功能完整。

I found the following solution, but it is very slow because I have to loop through every record. 我找到了以下解决方案,但是它很慢,因为我必须遍历每条记录。 Despite the fact I have implemented paging in breeze the loop still hits every single record, though it only returns one page. 尽管我已经实现了轻轻松松的分页,但是循环仍然会命中每条记录,尽管它只会返回一页。 I guess that is just how entity framework works. 我想这就是实体框架的工作方式。 My question is how do I populate extended properties without looping? 我的问题是如何填充扩展属性而不循环?

Here is my code that works, but it is slow. 这是我的代码,但是很慢。 Can I eliminate this loop and fill that extended property with a value? 我可以消除此循环,并用值填充该扩展属性吗?

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

    }

By the looks of it you are looping through the whole tables worth of data on the off chance someone gets some of the rows. 从外观上看,您正在遍历整个表中有价值的数据,这是某人偶然获得某些行的机会。 I'm not familiar with Breeze but I have worked with OData before so hopefully this solution will work for you. 我对Breeze并不熟悉,但是我曾经与OData合作过,所以希望该解决方案对您OData

I suggest that you stop exposing IQueryable<> and manage the query internally. 我建议您停止公开IQueryable<>并在内部管理查询。 This will enable you to add the additional information to only those records that you are returning to the client. 这将使您可以将附加信息仅添加到要返回给客户端的那些记录。 Here's some rough code to point you in the right direction: 以下是一些粗略的代码,可为您指明正确的方向:

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

and the using s using s

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

Thanks everyone for the direction. 谢谢大家的指导。 The suggestion that came the closest was the one about using oData. 最接近的建议是关于使用oData的建议。 I researched eager loading, but that seems to apply to joining entities and these properties cannot be combined. 我研究了热切的加载,但这似乎适用于连接实体,并且这些属性无法合并。 I will probably do more research with "include" to determine if it can be used to load a single property, but I couldn't find any documentation on it used that way. 我可能会对“ include”进行更多的研究,以确定它是否可以用于加载单个属性,但是我找不到使用该方法的任何文档。 Another thing that came close was projection, but EF doesn't allow projecting to the same type. 与之接近的另一件事是投影,但是EF不允许将其投影到同一类型。 I could have projected to a partial class, but then I would loose the MetaData that breeze needs. 我本可以将其投影到局部类中,但随后我会松散微风所需的MetaData。 If not for breeze that would have been a really nice solution. 如果不是微风吹拂,那将是一个非常不错的解决方案。 In the end, while Breeze does support oData it has too many limitations (such as cannot be cached), so I wanted to stay with IQueryable. 最后,尽管Breeze确实支持oData,但它有太多限制(例如无法缓存),所以我想继续使用IQueryable。

This is what I came up with. 这就是我想出的。 It now only loops through the current page, but it still gets a count on the main query so Breeze can do paging on the client. 现在,它仅循环浏览当前页面,但仍可对主查询进行计数,因此Breeze可以在客户端上进行页面调度。 This is all possible because Breeze allows me to send get parameters so I can offload the paging to the server. 这一切皆有可能,因为Breeze允许我发送get参数,以便将分页卸载到服务器。 This took tons of research and it still isn't perfect, but it does load very fast so I have to move on for now. 这花费了大量的研究,但仍然不是很完美,但是它的加载速度非常快,因此我现在必须继续。

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

    }

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

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