Правильный метод удаления более 2100 строк (по идентификатору) с помощью Dapper - PullRequest
10 голосов
/ 30 марта 2012

Я пытаюсь использовать Dapper для поддержки доступа к данным для моего серверного приложения.

В моем серверном приложении есть другое приложение, которое сбрасывает записи в мою базу данных со скоростью 400 в минуту.

Мое приложение извлекает их партиями, обрабатывает и затем удаляет их из базы данных.

Поскольку данные продолжают поступать в базу данных во время обработки, у меня нет хорошего способа сказать delete from myTable where allProcessed = true.

Однако я знаю значение PK удаляемых строк. Поэтому я хочу сделать delete from myTable where Id in @listToDelete

Проблема в том, что если мой сервер отключается хотя бы на 6 минут, у меня есть более 2100 строк для удаления.

Поскольку Dapper принимает мой @listToDelete и превращает каждый из них в параметр, мой вызов удалить не удастся. (Причинение моей очистки данных, чтобы получить еще дальше.)

Как лучше всего справиться с этим в Dapper?

ПРИМЕЧАНИЯ: Я посмотрел на Tabled Valued Parameters, но из того, что я вижу, они не очень производительные . Эта часть моей архитектуры является узким местом в моей системе, и мне нужно быть очень очень быстрым.

Ответы [ 3 ]

14 голосов
/ 30 марта 2012

Один из вариантов - создать временную таблицу на сервере, а затем использовать средство массовой загрузки, чтобы загрузить все идентификаторы в эту таблицу одновременно. Затем используйте предложение join, EXISTS или IN, чтобы удалить только те записи, которые вы загрузили в свою временную таблицу.

Массовая загрузка - это хорошо оптимизированный путь в SQL Server, и он должен быть очень быстрым.

Например:

  1. Выполнить инструкцию CREATE TABLE #RowsToDelete(ID INT PRIMARY KEY)
  2. Использование массовой загрузки для вставки ключей в #RowsToDelete
  3. Выполнить DELETE FROM myTable where Id IN (SELECT ID FROM #RowsToDelete)
  4. Выполнить DROP TABLE #RowsToDelte (таблица также будет автоматически удалена, если вы закроете сеанс)

(Предполагая Dapper) пример кода:

conn.Open();

var columnName = "ID";

conn.Execute(string.Format("CREATE TABLE #{0}s({0} INT PRIMARY KEY)", columnName));

using (var bulkCopy = new SqlBulkCopy(conn))
{
    bulkCopy.BatchSize = ids.Count;
    bulkCopy.DestinationTableName = string.Format("#{0}s", columnName);

    var table = new DataTable();                    
    table.Columns.Add(columnName, typeof (int));
    bulkCopy.ColumnMappings.Add(columnName, columnName);

    foreach (var id in ids)
    {
        table.Rows.Add(id);
    }

    bulkCopy.WriteToServer(table);
}

//or do other things with your table instead of deleting here
conn.Execute(string.Format(@"DELETE FROM myTable where Id IN 
                                   (SELECT {0} FROM #{0}s", columnName));

conn.Execute(string.Format("DROP TABLE #{0}s", columnName));
5 голосов
/ 30 марта 2012

Чтобы этот код работал, я пошел темной стороной.

Так как Даппер делает мой список параметров. И SQL Server не может обрабатывать много параметров. (Мне никогда не нужны были даже двузначные параметры). Мне пришлось идти с динамическим SQL.

Итак, вот мое решение:

string listOfIdsJoined = "("+String.Join(",", listOfIds.ToArray())+")";
connection.Execute("delete from myTable where Id in " + listOfIdsJoined);

Прежде чем все схватят свои факелы и вилы, позвольте мне объяснить.

  • Этот код выполняется на сервере, единственным входом которого является поток данных из системы мэйнфреймов.
  • Список, который я динамически создаю, представляет собой список длинных / больших позиций.
  • Длинные / большие буквы взяты из столбца Identity.

Я знаю, что создание динамического SQL - это плохо, но в этом случае я просто не понимаю, как это ведет к угрозе безопасности.

2 голосов
/ 01 марта 2016

Превосходный запрос списка объектов, имеющих параметр в качестве свойства, поэтому в приведенном выше случае список объектов с идентификатором Id будет работать.

connection.Execute("delete from myTable where Id in (@Id)", listOfIds.AsEnumerable().Select(i=> new { Id = i }).ToList());

Это будет работать.

...