Entity Framework SqlQuery Nullable Fields - PullRequest
0 голосов
/ 04 января 2019

Я использую Entity Framework SqlQuery для извлечения данных.

Вот код:

Context.Database.SqlQuery<MyModel>("exec dbo.MySP @StartDate, @EndDate", Params.ToArray()).ToListAsync();

и MyModel класс

public class MyModel
{
    public int? Code{ get; set; }
    public string Name{ get; set; }
    public DateTime? InsertDate { get; set; }
}

Проблема в том, что столбцы, которые можно обнулять, превращаются в Null во всех строках, когда в моем результате хранимой процедуры есть несколько столбцов Null. Но когда я удаляю эти Null столбцы в хранимой процедуре, все работает нормально.

ОБНОВЛЕНИЕ : вот хранимая процедура

ALTER PROCEDURE [dbo].[MySP] 
    @StartDate DATETIME = NULL,
    @EndDate DATETIME = NULL
AS
BEGIN
    CREATE TABLE #LastUpdates (Code INT, InsertDate DATETIME)

    SET NOCOUNT ON;

    INSERT INTO #LastUpdates 
        SELECT
            StoreCode,
            MAX(InsertDate)
        FROM 
            [dbo].[History]
        WHERE 
            (@StartDate IS NULL OR DATEDIFF(DAY, InsertDate, @StartDate) <= 0 )
            AND (@EndDate IS NULL OR DATEDIFF(DAY, InsertDate, @EndDate) >= 1)
        GROUP BY 
            StoreCode

    SELECT DISTINCT
        store.Name as Name,
        store.Code as Code,
        Updates.InsertDate AS InsertDate
    FROM 
        #LastUpdates AS Updates 
    RIGHT JOIN 
        [Stores] AS store ON Updates.Code = store.Code
    WHERE 
        store.IsDeleted = 0

    DROP TABLE #LastUpdates 
END

Ответы [ 2 ]

0 голосов
/ 04 января 2019
WHERE (@StartDate IS NULL OR DATEDIFF(DAY,InsertDate,@StartDate) <= 0 )
   AND (@EndDate IS NULL OR DATEDIFF(DAY,InsertDate,@EndDate) >= 1)

Игнорирует ваши параметры, когда они нулевые. Однако это все еще не обрабатывает нуль InsertDates. DATEDIFF вернет ноль для нуля InsertDates.

Вам нужно добавить (InsertDate is null) OR к остальной части вашего запроса, если вы хотите вернуть все нулевые InsertDates.

WHERE (InsertDate is null) OR ((@StartDate IS NULL OR DATEDIFF(DAY,InsertDate,@StartDate) <= 0 )
   AND (@EndDate IS NULL OR DATEDIFF(DAY,InsertDate,@EndDate) >= 1))

Возможно, вы захотите заменить DATEDIFF обычным синтаксисом сравнения дат для повышения производительности. InsertDate >= @StartDate будет быстрее, особенно если InsertDate имеет индекс. Я также считаю, что этот синтаксис делает более понятным, что вы ищете InsertDates между этими датами параметров или используете встроенный синтаксис between, который переводит его в синтаксис> = & <=. </p>

Перед добавлением SP SQL и ответом на вопросы:

Без лежащего в основе sql мы немного слепы, чтобы помочь вам, и нам также потребуется немного больше информации. Я задал пару вопросов (выше, в комментариях к вопросу), которые помогут нам лучше понять:

Что в стороне:

Я предполагаю, что вы делаете диапазон / между InsertDate против @StartDate и @EndDate. Поскольку эти параметры передаются в датах, null никогда не будет найден, если вы используете нормальный диапазон / между синтаксисами, такими как InsertDate >= @StartDate или InsertDate between @StartDate and @EndDate, поскольку NULL никогда не будет равняться дате, только если @StartDate или @EndDate равно NULL.

Если вы хотите вернуть все null InsertDates, вам нужно добавить к вашему запросу что-то вроде:

select field1,field2 from table1
where (InsertDate is null) or (InsertDate >= @StartDate and InsertDate <= @EndDate)

Если @StartDate или @EndDate равно нулю и вы хотите, чтобы это означало игнорировать параметр, тогда вам нужно переписать базовый SQL в хранимой процедуре, чтобы обработать не только InsertDate >= @StartDate.

Это должно было бы выглядеть как (@StartDate is null or InsertDate >= @StartDate).

То же самое должно быть сделано для параметра @EndDate.

0 голосов
/ 04 января 2019

Ваша процедура должна вернуть все свойства вашей модели (с таким же именем). Если процедура возвращает какие-либо другие поля и ваша модель ожидает их, вы получите ошибку.

Запрос возвращает все строки из истории и это право объединяет хранилища на основе условий. Если в хранилищах не найдено ни одной записи, запись из истории все еще включается в набор записей. Вам, вероятно, нужно ВНУТРЕННЕЕ СОЕДИНЕНИЕ.

Похоже, EF (хотя бы в одной точке) вернул нулевую строку. Поэтому вместо выбора * вы должны явно назвать столбцы и убедиться, что PK (или какой-либо другой столбец) будет первым.

Примечание: Я думаю, что почти всегда можно избежать RIGHT JOIN; запросы с LEFT JOIN намного легче читать и понимать.

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