SelectMany将查询转换为可枚举列表。如何避免呢?

时间:2018-08-17 21:46:28

标签: c# entity-framework entity-framework-6

我有一个MVC控制器操作,该操作以这种方式进行数据库查询:

var marcaciones = db.Marcacion

其中db是Entity Framework中的数据库上下文,而Marcacion是数据库表。该指令之后,marcaciones类型变为

System.Data.Entity.DbSet`1[CasinosCloud.Models.Marcacion]

这允许在框架实际在数据库中执行查询之前添加任何过滤器。

到目前为止,很好。

但是,根据特定条件,marcaciones变量是以不同的方式分配的。

数据库模型使得数据库中的marcaciones实体是另一个实体的子代。要获得该marcaciones列表,我可以这样做:

var marcaciones = trabajador.ServicioSupervisado.SelectMany(s => s.Marcacion).AsQueryable();

从上面的说明可以推断,trabajador是具有许多ServicioSupervisado实体的父数据库实体,而这些实体又可以具有许多Marcacion实体。

由于marcaciones变量与我之前显示的marcaciones变量相同,因此我必须转换为Queryable

执行上述指令后,marcaciones类型变为;

{System.Linq.Enumerable+<SelectManyIterator>d__17`2
    [CasinosCloud.Models.Servicio,CasinosCloud.Models.Marcacion]}

这意味着查询实际上已转换为可枚举列表。

在不应用其他过滤器的情况下,所有方法均有效。当我添加查询过滤器时,我遇到了第二种形式的问题。首先,整个网页速度较慢,因为所有筛选器都应用在内存列表中,而不是数据库中,其次,字符串比较存在问题,特别是当数据库中的文件以大写形式存储时,我试图以小写形式查找文本。当然,在这种情况下什么也找不到。

我认为通过解决类型问题可以减少问题。为什么在调用SelectMany之后实际上执行查询并将其转换为可枚举列表?有没有办法避免这种情况以及所有在数据库中执行的情况?也许我应该不使用SelectMany来重写该指令。我尝试使用db.Marcacion.Insersect()与此代码进行交集,但是出现相同的问题:

trabajador.ServicioSupervisado.SelectMany(s => s.Marcacion)

编辑:

我要在数据库中执行的查询采用以下形式:

第一种方式:

SELECT m.*
FROM Marcacion m

第二种方式:

SELECT m.*
FROM Marcacion m
INNER JOIN Servicio s ON s.ServicioId = m.ServicioId
INNER JOIN Trabajador t ON t.TrabajadorId = s.TrabajadorId
WHERE t.TrabajadorId = 1069

编辑2:

第二种方式,我尝试了:

marcaciones = marcaciones.Where(m => trabajador.ServicioSupervisado.Any(s => s.ServicioId == m.ServicioId));

此后,当在数据库中实际执行查询时,会发生此错误:

  

System.NotSupportedException:'无法创建类型为'CasinosCloud.Models.Servicio'的常量值。在这种情况下,仅支持原始类型或枚举类型。'

1 个答案:

答案 0 :(得分:-1)

我通过这样编写查询来解决它:

var servicios = trabajador.ServicioSupervisado.Select(s => s.ServicioId);
marcaciones = marcaciones.Where(m => servicios.Any(s => s == m.ServicioId));

这种方式在我调用ToList()时执行查询,并且在我提到的两种情况下都有效,因为查询直接在应用了所有过滤器的数据库中运行,所以在这两种情况下都非常快。

通过查看数据库日志,实体框架执行的最终查询为:

SELECT 
    [Extent1].[MarcacionId] AS [MarcacionId], 
    [Extent1].[MonitorId] AS [MonitorId], 
    [Extent1].[TrabajadorId] AS [TrabajadorId], 
    [Extent1].[EmpresaId] AS [EmpresaId], 
    [Extent1].[ServicioId] AS [ServicioId], 
    [Extent1].[MarcacionFechaHora] AS [MarcacionFechaHora], 
    [Extent1].[MarcacionEntradaSalida] AS [MarcacionEntradaSalida], 
    [Extent1].[MarcacionChecksum] AS [MarcacionChecksum], 
    [Extent1].[MarcacionEquipo] AS [MarcacionEquipo], 
    [Extent1].[MarcacionEsManual] AS [MarcacionEsManual], 
    [Extent1].[MarcacionCreadoEn] AS [MarcacionCreadoEn], 
    [Extent1].[MarcacionActualizadoEn] AS [MarcacionActualizadoEn], 
    [Extent1].[MarcacionIndice] AS [MarcacionIndice]
FROM  [dbo].[Marcacion] AS [Extent1]
INNER JOIN [dbo].[Trabajador] AS [Extent2] ON [Extent1].[TrabajadorId] = [Extent2].[TrabajadorId]
WHERE ( EXISTS (SELECT 
    1 AS [C1]
    FROM  ( SELECT 1 AS X ) AS [SingleRowTable1]
    WHERE 3 = [Extent1].[ServicioId]
)) AND ([Extent2].[TrabajadorNombres] + N' ' + [Extent2].[TrabajadorApellidos] LIKE @p__linq__0 ESCAPE N'~') AND ([Extent1].[MarcacionFechaHora] >= @p__linq__1) AND ([Extent1].[MarcacionFechaHora] <= @p__linq__2)