首页 > 解决方案 > 使用 LINQ 和实体框架时如何避免重复 ToList?

问题描述

我有一个DbSet<T>我需要投射到不同类型上的东西。对于投影,我使用Select.

如果我直接打电话给Select我的DbSet<T>喜欢:

private IEnumerable<PersonPOCO> _getPersons(ILocator loc)
{
    using(var service = loc.GetService())
    {
        return service.GetPersons().Select(p => Mapper.ToPoco(p));
    }
}

这将抛出一个NotSupportedException因为Select实体框架无法识别(这很明显)。

所以我需要通过调用来“具体化”列表ToList()

private IEnumerable<PersonPOCO> _getPersons(ILocator loc)
{
    using(var service = loc.GetService())
    {
        return service.GetPersons()
                      .ToList()
                      .Select(p => Mapper.ToPoco(p));
    }
}

如果我这样离开它,Select那么只有在真正枚举列表时才会评估“懒惰”。但是到那时,服务使用的 Context 将被释放(在using语句之外),所以我将拥有一个DbContextDisposedException.

所以我需要直接枚举里面的列表using

private IEnumerable<PersonPOCO> _getPersons(ILocator loc)
{
    using(var prov = loc.GetService())
    {
        return prov.GetPersons()
            .ToList()
            .Select(p => Mapper.ToPOCO(p))
            .ToList();
    }
}

有没有办法避免ToList()在同一条指令中调用两次?

标签: c#entity-frameworklinq

解决方案


这里的问题是 EF 不知道如何处理DataViewMapper.ToPOCO. 您可以使用AsEnumerable()切换到 LINQ-to-Objects:

using (var prov = arg.GetProvider())
{
    return prov.GetParamTypes()
        .AsEnumerable()
        .Select(p => DataViewMapper.ToPOCO(p))
        .ToList();
}

这避免了中间列表/数组/等分配。


推荐阅读