如何在将实体列表转换为视图模型之前将过滤/分页应用于实体列表,以便我们避免在内存中实现整个列表?

时间:2012-11-29 21:21:20

标签: linq asp.net-mvc-4 asp.net-web-api odata

我正在创建一个WebAPI供移动应用程序以及我们的ASP.NET MVC4 webapp使用。我们正在使用庞大的数据库,因此我们需要尽可能避免实现实体列表。我们的WebAPI返回JSON。

情况很简单......收到了许可证列表的请求,但必须对其进行分页,因为有500,000条记录可以返回。在将它们转换为返回的viewmodel列表之前,如何将分页/过滤应用于IQueryable实体列表?

以下是我正在使用的一些测试代码......

    // Get the list of licenses, but page them.
    // GET api/<controller>
    //[Queryable] 
    public IQueryable<LicenseViewModel> Get()
    {
        Mapper.CreateMap<LicenseEntity, LicenseViewModel>();
        Mapper.AssertConfigurationIsValid();

        List<LicenseViewModel> vms = new List<LicenseViewModel>();
        using (var repo = new LicenseRepository())
        {
            // Get the IQueryable<LicenseEntity> list...
            // IS THERE SOME WAY TO APPY PAGING/FILTERING HERE?
            var entities = repo.List();

            // Convert them to viewmodels.  ARGGG! This will materialize the huge list
            // if we cannot applyfiltering/paging in the previous step.
            foreach (var item in entities)
            {
                var vm = Mapper.Map<LicenseEntity, LicenseViewModel>(item);
                list.Add(vm);
            }
        }

        return vms.AsQueryable();
    }

我尝试了以下操作,但在尝试展开列表并查看结果时收到“儿童无法回避”错误。

            using (var repo = new LicenseRepository())
            {
                // Get the list of entities...
                var list = repo
                    .List()
                    .Select(x => Mapper.Map(x, new LicenseViewModel()));

                return list;
            }

感谢您的时间和建议,

麦克

4 个答案:

答案 0 :(得分:0)

不确定这是如何映射到Web API的,但主体是相同的。

WCF Dataservices基本相同,但我相信目前有一些额外功能,您可以设置页面大小如下:

 public static void InitializeService(DataServiceConfiguration config)
 {
        config.SetEntitySetPageSize("*", 20);
 }

&#34; *&#34;插入您的实体集名称。

通过设置此项,Feed将包含一个延续令牌,客户端可以使用该令牌来请求下一页。

在您的存储库中,您可能需要根据数据源手动处理Take和Skip功能。

如果网址包含?$ top = 10&amp; $ skip = 0,那么您可以将其添加到您的数据源请求中,请参阅下面的示例。

using (var repo = new LicenseRepository())
{
     // Get the list of entities...
     var list = repo                        
     .Select(x => Mapper.Map(x, new LicenseViewModel()))
     .Skip(0)
     .Take(10);
     return list;
}

显然,根据网址的$ top和$ skip元素中的内容更改skip / take值。

答案 1 :(得分:0)

对于分页,您可以使用我们最近添加的ResultLimit功能。你可以说,

[Queryable(ResultLimit=10)] 

一次只能返回10个项目。

而且,最酷的部分是我们计算下一页链接。下一页链接是客户端为了获取下一页而应该遵循的链接。如果您使用的是ODataFormatter,则默认情况下,响应中会包含下一页链接。如果您使用不同的格式化程序,我们只计算链接但不要将其放入响应正文中,因为我们不知道它的格式。你可以编写一个消息处理程序或一个动作过滤器来从

中检索链接
Request.Properties['MS_NextPageLink'] 

并将其写入响应正文或响应标题或客户期望的任何位置。

答案 2 :(得分:0)

//获取LicenseEntity对象的IQueryable列表。 var entityList = LicenseRepository.List(adapter);

//将列表转换为IQueryable列表 // LicenseViewModel对象。 var vmList = entityList.Select(x =&gt; AutoMapper.Mapper.Map(x,new LicenseViewModel()));

答案 3 :(得分:0)

我找到了将域实体投影到视图模型的解决方案。如果您遇到与我相同的问题,请查看以下链接:

http://lostechies.com/jimmybogard/2011/02/09/autoprojecting-linq-queries/ http://www.devtrends.co.uk/blog/stop-using-automapper-in-your-data-access-code

顺便说一句,在一个我的域实体中,我有一个带有一些“计算”属性的部分类...其值是从数据库记录中的其他字段生成的属性。这些不能在域实体中,因为它们会干扰上述解决方案。我把它们移到我的ViewModel类,这是他们真正需要的地方,一切都很好。

希望这些信息有助于......

麦克