2017-05-30 62 views
-1

为什么EF生成一个查询,以便以下内容不生成结果行并且首先引发异常。尽管在结果中包含Count,为什么此EF查询不返回结果?

IQueryable<EntityName> repo = GetQuery<EntityName>(); 
IQueryable<EntityName> query = repo.Where(x => x.Discriminator == 1); 
var result = repo.Select(x => new 
{ 
    TotalRecords = query.Count(), 
    Results = query.Skip(request.Skip).Take(request.Take).ToList() 
}).First(); 

这个技巧允许我在EF中的单个数据库调用下运行多个查询;我打电话给任意库repo,并返回一个新的对象,其中每个属性是一个子查询。只要存在query IQueryable中的记录,就会生效。然而,我惊讶地发现当query中没有记录时,没有任何返回(即query.Count()不包含在结果中)。我认为即使query中没有实体,这样的查询也应该产生结果行,因为它涉及Count(),但它不返回任何内容。我怀疑这与EF必须在底层生成一个单一的结果集有关。

+0

不要紧,什么是'Select'内,结果计数总是一样的输入设置。 'First'(或'Take(1)')可以将其限制为最大1,即0或1.这基本上是SQL查询行为,而不是EF。 –

回答

1

这是真的,Count方法总是返回一个值,但与你的绝招的问题是,它是一个外select查询(repo.Select(x => ...)的一部分,所以结果集的基数被包含的记录数控制在外部查询repo - 当它为空时,结果将为空,因此FirstOrDefault将返回null并且根本不会执行里面的子查询。

不同的数据库有解决这些问题的不同的机制 - 例如,甲骨文将使用称为dual特殊的单记录表,SQL Server允许SELECT没有FROM等,但由于EF是通用的,它不能使用任何这些(以及,从技术上讲,如果整个事物是以标准方式抽象出来的,并且实际的实现被委托给实际的提供者,但它没有完成)。

尽管如此LINQ提供了一种方法(由EF支持)来强制一组通过使用DefaultIfEmpty方法返回至少1结果。通过使用

var result = repo.DefaultIfEmpty().Select(x => ... 

现在,因为子查询是完全无关的x,可以消除用于生产单外结果db表:应该在外部查询应用的Select操作之前

var result = repo.Where(_ => false).DefaultIfEmpty().Select(x => ... 

这里repo可以是任何IQueryable<T>只要它从DbContext起源,以获得正确IQueryProvider

相关问题