实体框架从表达式生成错误的参数类型

时间:2019-03-10 13:31:57

标签: c# sql-server entity-framework

EF正在创建一个接收int作为参数的查询。它应该是一个varchar。

我有这个生成表达式的C#代码

Expression<Func<Documento, bool>> query = (t => (string)t.NumeroDocumento.ToString() == (string)numeroOriginal.ToString());

var documento = documentoRepository.Obter(query, propriedadesIncluidas: "PapelPessoa.Pessoa");

Documento.Numero documento是一个字符串。数据库表中对应的文件是varchar(50)。 numeroOriginal 也是一个字符串。

以及此代码(用于存储库中的对象(获取)

private T Obter(Expression<Func<T, bool>> filtro, string propriedadesIncluidas)
    {
        IQueryable<T> query = dbSet;

        if (filtro != null)
            query = query.Where(filtro);

        if (!string.IsNullOrWhiteSpace(propriedadesIncluidas))
        {
            foreach (var includeProperty in propriedadesIncluidas.Split
                (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                query = query.Include(includeProperty);
        }

        return query.FirstOrDefault();
    }

当EF创建sql查询时,它将创建此查询(从调试器获取)

SELECT     [Extent1].[id] AS [id],     [Extent1].[numero_documento] AS [numero_documento],     
-- Removed for clariry
FROM [dbo].[DOCUMENTO] AS [Extent1]    
WHERE [Extent1].[numero_documento] = (CASE WHEN (@p__linq__0 IS NULL) THEN N'' ELSE @p__linq__0 END)

替换参数后,它将转换为

SELECT     [Extent1].[id] AS [id],     [Extent1].[numero_documento] AS [numero_documento],     
-- Removed for clariry
FROM [dbo].[DOCUMENTO] AS [Extent1]    
WHERE [Extent1].[numero_documento] = 47837

正确的查询应该是

SELECT     [Extent1].[id] AS [id],     [Extent1].[numero_documento] AS [numero_documento],     
-- Removed for clariry
FROM [dbo].[DOCUMENTO] AS [Extent1]    
WHERE [Extent1].[numero_documento] = '47837'

两者都能工作,但是第二个要比第一个快得多(我的意思是说MUCH)。我都在SQL Management Studio中运行。 EF弄错了参数类型吗?我该如何解决?我需要更改代码或数据库吗?我的表格的EF配置是否错误?

这是EF对象:

[Table("DOCUMENTO")]
    public class Documento : EntidadeBase
    {

        [Column("numero_documento", TypeName = "varchar")]
        [Display(Name = "Numero")]
      public string NumeroDocumento { get; set; }

// removed for clarity
}

这是表格

CREATE TABLE [dbo].[DOCUMENTO](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [numero_documento] [varchar](50) NULL,
-- removed for clarity
}

1 个答案:

答案 0 :(得分:0)

我怀疑在这个实体/列周围配置了一些不同的东西,或者可能是使它崩溃的上下文。我试图重现该问题,但没有遇到相同的问题:

我在一个测试表中添加了一个varchar列,并将其输入数值进行搜索。

与您拥有的演员相同:

Expression<Func<Course, bool>> where = (x => (string)x.SomeNumber.ToString() == (string)testId.ToString());

我从EF获得了一条SQL语句:

exec sp_executesql N'SELECT 
    [Extent1].[CourseId] AS [CourseId], 
    [Extent1].[Name] AS [Name], 
    [Extent1].[SomeNumber] AS [SomeNumber]
    FROM [dbo].[Courses] AS [Extent1]
    WHERE ((CASE WHEN ([Extent1].[SomeNumber] IS NULL) THEN N'''' ELSE [Extent1].[SomeNumber] END) = (CASE WHEN (@p__linq__0 IS NULL) THEN N'''' ELSE @p__linq__0 END)) OR ((CASE WHEN ([Extent1].[SomeNumber] IS NULL) THEN N'''' ELSE [Extent1].[SomeNumber] END IS NULL) AND (CASE WHEN (@p__linq__0 IS NULL) THEN N'''' ELSE @p__linq__0 END IS NULL))',N'@p__linq__0 nvarchar(4000)',@p__linq__0=N'12'
go

过滤器显示为N'12'

如果我删除了不必要的强制类型转换(DB列为varchar(50),并且所使用的变量为字符串)。

Expression<Func<Course, bool>> where = (x => x.SomeNumber == testId);

导致:

exec sp_executesql N'SELECT 
    [Extent1].[CourseId] AS [CourseId], 
    [Extent1].[Name] AS [Name], 
    [Extent1].[SomeNumber] AS [SomeNumber]
    FROM [dbo].[Courses] AS [Extent1]
    WHERE ([Extent1].[SomeNumber] = @p__linq__0) OR (([Extent1].[SomeNumber] IS NULL) AND (@p__linq__0 IS NULL))',N'@p__linq__0 nvarchar(4000)',@p__linq__0=N'12'
go

再次,N'12'

当我使用TypeName =“ varchar”为列分配属性时,则nvarchar(4000)和N'12'变为varchar(8000)和'12'。在第二个示例中,然而在第一个示例中(带有额外的强制转换)奇怪地是,它仍然将参数称为nvarchar。

构建表达式时,可以尝试从项目中删除强制类型转换吗?如果需要强制转换值,请尝试仅强制转换值,而不是实体端属性: 即

Expression<Func<Documento, bool>> query = (t => t.NumeroDocumento == numeroOriginal);

Expression<Func<Documento, bool>> query = (t => t.NumeroDocumento == numeroOriginal.ToString()); // if numeroOriginal may not be a string.

除此之外,您还使用什么版本的Entity Framework?