Удержание соединения с базой данных при использовании «yield» - PullRequest
0 голосов
/ 02 марта 2020

У меня есть базовый c класс данных (сокращен для краткости и что он компилируется):

public static class Database
{
    public static IEnumerable<T> GetRecords<T>(string query, Func<IDataReader, T> mappingFunction)
    {
        var connectionString = "";
        using (var connection = new SqlConnection(connectionString)) 
        {
            using (var command = new SqlCommand(query, connection)) 
            {
                using (var reader = command.ExecuteReader(CommandBehavior.CloseConnection)) 
                {
                    while(reader.Read()) {
                        yield return mappingFunction(reader);
                    }
                }
            }
        }
    }
}

var records = Database.GetRecords("SELECT FirstName FROM [Order]", reader => 
                                          new Order { FirstName = reader["FirstName"].ToString() });

public class Order {
    public string FirstName;
}           

У меня есть другая версия, которая возвращает List<T> как таковую:

using (var reader = command.ExecuteReader(CommandBehavior.CloseConnection)) 
{
    var items = new List<T>();
    while(reader.Read()) {
        items.Add(mappingFunction(reader));
    }
    return items;
}

Я добавляю IEnumerable<T> для какой-то итерационной части приложения, доступной только для чтения, которая используется для генерации отчетов. Он извлекает много строк и должен выполнить некоторое сопоставление для проецирования полей базы данных на модель для отчета.

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

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

Я генерирую отчеты, используя библиотеку CsvHelper, которая может работать с IEnumerable, поэтому я решил, что IEnumerable из БД обратно в код клиента уменьшит использование памяти, поскольку перечислимое значение равно только

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

Полагаю, здесь это компромисс между использованием памяти и SQL время соединения

var orders = Database.GetRecords("SELECT [things] FROM [Order]", reader =>  MapOrder(reader));

IEnumerable<ReportRecord>() GetRecords(IEnumerable<Order> orders) 
{
    foreach (var order in orders) 
    {
        var reportRecord = new ReportRecord();
        var items = GetOrderItems(order);

        // other queries, calculations etc

        yield return reportRecord;
    }
}

// save to disk using CsvHelper and output file
CsvHelper.Save(GetRecords(), filepath); // fake code -- but uses the IEnumerable instead of materialised list
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...