Entity Framework генерирует неверный тип параметра из выражения - PullRequest
3 голосов
/ 10 марта 2019

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 documentmento представляет собой строку. Соответствующее поле в таблице базы данных - это varchar (50). цифраОригинал также является строкой.

и этот код для obter (get) в хранилище

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'

Оба работают, но второе намного (и я имею в виду НАМНОГО) быстрее, чем первое. Я запускал оба в студии управления SQL. 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 голосов
/ 11 марта 2019

Я подозреваю, что что-то настроено немного по-другому вокруг этой сущности / столбца или, возможно, в контексте, который вызывает это.Я пытался воспроизвести проблему, но не сталкивался с той же проблемой:

Я добавил столбец varchar в одну из моих тестовых таблиц и ввел числовые значения для поиска.

С приведениями, такими же, как у вас:

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

Я получаю оператор SQL от EF:

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ты используешь?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...