У меня есть функция BulkCopyIntoTable, которая фильтрует таблицу данных на основе максимального целого числа таблицы, в которую я вставляю, и вставляет данные, превышающие это целое число. Я использую возвращаемое целое число (количество вставленных записей) для отправки электронного письма со сводной статистикой. Должен ли я сделать эту функцию асинхронной? Один из разработчиков в моей команде сказал, что есть вероятность, что функция отправки электронной почты сможет отправить без всех данных из этой функции, если я не сделаю ее асинхронной, но я подумал, что если я оставлю ее синхронизированной, она должна дать тот же результат, что и при ожидании функции? Это просто запланированная задача, которая запускается один раз в день и загружает данные в две таблицы, из которых только читаются. приложению не нужно обновлять пользовательский интерфейс или делать что-либо еще, поэтому не слишком ли оно делает, чтобы пометить эту асинхронность?
public static int BulkCopyIntoTable(DataTable dataTable, string inputConnectionString, string tableName)
{
try
{
if (dataTable == null || dataTable.Rows.Count == 0)
{
logger.Error($"No rows parsed for table {tableName}. Skipping bulk copy.");
hasError = true;
return 0;
}
string idField = TRANSACTIONS_ID_FIELD;
if (tableName == WIRES_STAGING_TABLE || tableName == WIRES_TABLE)
idField = WIRES_ID_FIELD;
using(var conn = new SqlConnection(inputConnectionString))
{
conn.Open();
// 1) find the largest id from the table
DataTable? filteredTable = FilterAndSortTableForNewRecords(dataTable, tableName, idField, conn);
if (filteredTable == null)
return 0;
// 3) BULK COPY only net new records into staging table
using (var copy = new SqlBulkCopy(conn, SqlBulkCopyOptions.CheckConstraints | SqlBulkCopyOptions.KeepIdentity, null))
{
copy.DestinationTableName = tableName;
copy.BatchSize = 10_000;
copy.BulkCopyTimeout = 3000;
copy.ColumnOrderHints.Add(new SqlBulkCopyColumnOrderHint(idField, SortOrder.Ascending));
foreach (DataColumn col in filteredTable.Columns)
{
copy.ColumnMappings.Add(col.ColumnName, col.ColumnName);
}
copy.WriteToServer(filteredTable);
}
logger.Info($"Copying to table: {tableName} complete");
return filteredTable.Rows.Count;
}
}
catch (SqlException ex)
{
hasError = true;
logger.Error($"ERROR: Bulk insert for {tableName}: {ex.Message} (Number={ex.Number}, State={ex.State})");
}
catch (Exception e)
{
hasError = true;
logger.Error($"ERROR: Bulk insert for {tableName}: {e.Message}");
}
return 0;
}
private static DataTable FilterAndSortTableForNewRecords(DataTable dataTable, string tableName, string idField, SqlConnection conn)
{
int largestId;
string sql = $"SELECT MAX({idField}) FROM " + tableName;
using (var cmd = new SqlCommand(sql, conn))
{
largestId = (int)(cmd.ExecuteScalar());
}
logger.Info($"Got the max id of {tableName}. Filtering on max id: {largestId}");
//2 ) filter only records with higher ids than the largest one found in table
var filteredRows = dataTable.AsEnumerable()
.Where(r => r.Field(idField) > largestId)
.OrderBy(r => r.Field(idField));
DataTable filteredTable;
if (filteredRows.Any())
{
filteredTable = filteredRows.CopyToDataTable();
}
else
{
logger.Info($"No net new records found for table {tableName}. Largest id in table: {largestId}");
return null;
}
logger.Info($"Inserting {filteredTable.Rows.Count} rows...");
return filteredTable;
}
}