Возврат DataReader из уровня данных в операторе Using

Вы можете установить желаемый формат:

dataGridViewCellStyle.Format = "dd/MM/yyyy";
this.date.DefaultCellStyle = dataGridViewCellStyle;
// date being a System.Windows.Forms.DataGridViewTextBoxColumn
10
задан Joel Coehoorn 11 May 2009 в 21:19
поделиться

4 ответа

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

public IEnumerable<IDataRecord> GetSomeData(string filter)
{
    string sql = "SELECT * FROM [SomeTable] WHERE SomeColumn= @Filter";

    using (SqlConnection cn = new SqlConnection(GetConnectionString()))
    using (SqlCommand cmd = new SqlCommand(sql, cn))
    {
        cmd.Parameters.Add("@Filter", SqlDbType.NVarChar, 255).Value = filter;
        cn.Open();

        using (IDataReader rdr = cmd.ExecuteReader())
        {
            while (rdr.Read())
            {
                yield return (IDataRecord)rdr;
            }
        }
    }
}

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

Обратной стороной является то, что читателям, имеющим более одного набора результатов, будет неудобно, но это очень редко.

Обновление
С тех пор, как я начал играя с этим шаблоном в 2009 году, я понял, что лучше всего, если я также сделаю его общим IEnumerable и добавьте параметр Func для преобразования состояния DataReader в бизнес-объекты в цикле. В противном случае могут возникнуть проблемы с отложенной итерацией, из-за которых вы каждый раз будете видеть последний объект в запросе.

13
ответ дан 3 December 2019 в 16:30
поделиться

В такие времена я считаю, что лямбды могут быть очень полезны. Учтите, что вместо уровня данных, предоставляющего нам данные, давайте дадим уровню данных наш метод обработки данных:

public void GetSomeData(string filter, Action<IDataReader> processor)
{
    ...

    using (IDataReader reader = cmd.ExecuteReader())
    {
        processor(reader);
    }
}

Тогда бизнес-уровень назовет его:

GetSomeData("my filter", (IDataReader reader) => 
    {
        while (reader.Read())
        {
            ...
        }
    });
3
ответ дан 3 December 2019 в 16:30
поделиться

То, что вам нужно, это поддерживаемый шаблон, вам нужно будет использовать

cmd.ExecuteReader(CommandBehavior.CloseConnection);

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

7
ответ дан 3 December 2019 в 16:30
поделиться

Я никогда не был большим поклонником того, чтобы уровень данных возвращал общий объект данных, так как это в значительной степени растворяет весь смысл разделения кода на его собственный уровень (как вы можете отключить слоев данных, если интерфейс не определен?).

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

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

0
ответ дан 3 December 2019 в 16:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: