【发布时间】:2021-05-11 08:45:28
【问题描述】:
我有一个DbSet<T>,我需要将其投影到不同的类型上。对于投影,我使用Select。
如果我直接在我的DbSet<T> 上拨打Select 就像:
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() 两次?
【问题讨论】:
-
EF 确实“识别”
Select,它不知道如何处理Mapper.ToPoco。那是什么? -
第二个
ToList是不必要的,因为第一个会立即枚举集合。只有Select被延迟评估,此时它将在内存中的列表上运行。 -
在
Select是AsEnumerable(),而不是ToList()之前,技术上你需要的(如果你不能重写Select以通过用映射表达式替换映射器调用来翻译)。跨度> -
@JohnathanBarclay 很好,是的,但是如果你要在本地缓冲数据,你不妨在投影之后再做,这样如果它被多次消耗,投影就不会重复
-
@MarcGravell 是的,你说得对。评论更多是因为 OP 认为省略第二个
ToList会导致异常。
标签: c# entity-framework linq