WHERE IN Raw SQL Запрос, используемый с ExecuteSqlCommand, не работающим для нескольких записей - PullRequest
0 голосов
/ 05 марта 2020

Я пытаюсь эффективно использовать запрос UPDATE при обновлении нескольких записей (вместо зацикливания для каждого Id).

У меня есть такой простой метод:

    public static async Task EfficientlyUpdateSentTimeforSomeTicketsAsync(List<int> Ids)
    {
        var parameters = Ids.Select((id, index) => new SqlParameter(string.Format("@p{0}", index), id));
        var parameterNames = string.Join(", ", parameters.Select(p => p.ParameterName));
        var query = string.Format("Update [TicketQueueTable] Set SentDatetime = {1} WHERE TicketQueueID IN ({0})", parameterNames, DateTime.Now);

        try
        {
            using (var db = GetDbContext())
            {
                var affectedRows = await db.Database.ExecuteSqlCommandAsync(query, parameters.ToArray());
            }
        }
        catch (Exception ex)
        {
            await LogErrorAsync(ex);
            throw ex;
        }
    }

Я получил помощь по такому вопросу: { ссылка }, но я не могу заставить эту работу. Меня поражает исключение:

Неверный синтаксис рядом с '2'

Для простоты, идентификаторы, которые я сейчас отправляю, new List<int>() { 1, 2 }.

Спасибо за ваше время.

Ответы [ 2 ]

3 голосов
/ 05 марта 2020

Строка, которую вы создаете, выглядит следующим образом

Update [TicketQueueTable] Set SentDatetime = 3/6/2020 2:30:18 AM WHERE TicketQueueID IN (@p0, @p1)

Если вы попытаетесь выполнить эту команду с помощью инструмента sql, например SQL Server Management Studio, вы получите эту ошибку.

Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '2'.

Плюс 2 в 2:30:18 подчеркнут красным.


У вас есть несколько вариантов:

  1. в кавычках даты и времени
var query = string.Format("Update [TicketQueueTable] Set SentDatetime = '{1}' WHERE TicketQueueID IN ({0})", parameterNames, DateTime.Now);
используйте функцию sql, чтобы получить текущее время сервера sql
var query = string.Format("Update [TicketQueueTable] Set SentDatetime = GETDATE() WHERE TicketQueueID IN ({0})", parameterNames, DateTime.Now); // GETDATE() for MSSQL NOW() for MySQL
передать дату и время в качестве параметра
public static async Task EfficientlyUpdateSentTimeforSomeTicketsAsync(List<int> Ids)
{
    var parameters = Ids.Select((id, index) => new SqlParameter(string.Format("@p{0}", index), id)).ToList();
    var parameterNames = string.Join(", ", parameters.Select(p => p.ParameterName));
    var query = string.Format("Update [TicketQueueTable] Set SentDatetime = @p{1} WHERE TicketQueueID IN ({0})", parameterNames, parameters.Count());

    parameters.Add(new SqlParameter($"@p{parameters.Count()}", DateTime.Now));
    try
    {
        using (var db = GetDbContext())
        {
            var affectedRows = await db.Database.ExecuteSqlCommandAsync(query, parameters.ToArray());
        }
    }
    catch (Exception ex)
    {
        await LogErrorAsync(ex);
        throw ex;
    }
}
1 голос
/ 05 марта 2020

Примерно так: (я не проверял, может быть, опечатка)

var parameterNames = string.Join(", ", Ids.Select(p => "("+ x.id.ToString()+")"));
var query = string.Format(@"Update TicketQueueTable 
                              Set SentDatetime = '{1}'
                             FROM TicketQueueTable
                             JOIN (
                               VALUES
                                {0}
                             ) AS L(ID) ON TicketQueueTable.Ticket.TicketQueueID = L.ID;", parameterNames, DateTime.Now)

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

...