Как я могу гарантировать, что мое соединение с базой данных будет закрыто при отложенном выполнении запроса linq? - PullRequest
1 голос
/ 31 мая 2011

У меня есть следующий метод:

public IEnumerable<Foo> GetFoo(int x, string y) 
{
    return from r in new GetFoo(x, y)
           select new Foo 
           {
               x = r.Get<int>("x"),
               y = r.Get<string>("y"),
               z = r.Get<DateTime?>("z"),
           };
 }

GetFoo - это класс, который содержит хранимую процедуру и реализует IEnumerable<DbDataReader>.Итак, r - это DbDataReader.Я хочу, чтобы он выполнил запрос, в котором объявлен синтаксис запроса, и вернул List<Foo>.
. Если этого не сделать, то, насколько я понимаю, вызывающая сторона может просто не выполнять итерацию всего списка, а затем соединение с базой данных не будетбыть закрытымЯ знаю, что могу просто поставить его в скобки и вызвать ToList (), но я хочу избежать этого, если это возможно.У нас более 200 хранимых процедур, и разработчику слишком легко пропустить добавление ToList ().

Есть ли что-то, что я могу реализовать, чтобы добиться желаемого?

Обновление

Это не linq to sql, я создал кастомкласс GetFoo, который реализует IEnumerable<DbDataReader>.Возвращаемое IEnumerator<DbDataReader> выглядит следующим образом:

private class Enumerator : IEnumerator<DbDataReader> {
    DbDataReader _;
    public Enumerator(DbDataReader r) { _ = r; }
    public DbDataReader Current { get { return _; } }

    public void Dispose() { _.Dispose(); }

    object System.Collections.IEnumerator.Current { get { return _; } }
    public bool MoveNext() { return _.Read(); }
    public void Reset() { throw new NotImplementedException(); }
}

Обновление 2

Я не могу принудительно вызвать ToList() и / или требовать List<Foo> быть возвращаемым типом этого метода и тому подобное.Отзыв разработчика должен поймать, не преобразовав его в список.К сожалению, если его пропустили там и в тестировании QA, приложение будет работать нормально.Я просто пытаюсь предотвратить ситуацию, когда соединение с базой данных можно оставить открытым.

Ответы [ 3 ]

1 голос
/ 31 мая 2011

Linq основан на отложенной загрузке. Когда вы вызываете ToList, он выполняет команду. В противном случае он не выполняет его. Так что ответ на ваши вопросы - нет. Однако я не уверен, что, возможно, контракты кода могут помочь в том, где вы помечаете методы, или вызываете вышеуказанный код в функциях, которые возвращают List. В этом случае разработчики будут обязаны вернуть список. В противном случае код не скомпилируется.

0 голосов
/ 31 мая 2011

return a List<Foo>

Очевидно, это не то, что вы делаете.Вы возвращаетесь IEnumerable<Foo>.Если вы вернете List<Foo>, ваши разработчики ничего не смогут сделать, кроме как вызвать ToList.

Если вы действительно не хотите этого делать, я бы порекомендовал создать какой-то QueryObject, которыйбудет содержать логику, которая есть в вашем методе.А затем вызовите его через некоторый вспомогательный класс, который внутренне вызовет ToList для него.Это также соответствовало бы принципу DRY.

Кроме того, вы, похоже, осуществляете только некоторый анализ возвращенного набора данных.Так что вам нужно реализовать только этот разбор:

public abstract class BaseStoredProcedureQuery<TReturn>
{
    protected abstract TReturn ParseRecord(DbDataReader r);

    protected IEnumerable<TReturn> ParseQuery(IEnumerable<DbDataReader> readers)
    {
        return readers.Select<DbDataReader,TReturn>(ParseRecord).ToList();
    }
}

public class Query1 : BaseStoredProcedureQuery<Foo>
{
    protected override Foo ParseRecord(DbDataReader r)
    {
        return new Foo
                   {
                       x = r.Get<int>("x"),
                       y = r.Get<string>("y"),
                       z = r.Get<DateTime?>("z"),
                   };
    }

    public IEnumerable<Foo> GetFoo(int x, string y)
    {
        return ParseQuery(GetFoo(x, y));
    }
}
0 голосов
/ 31 мая 2011

Некоторые, где вам нужно будет изменить тип возвращаемого значения, чтобы это произошло.Либо вы можете изменить все возвращаемые типы таких методов на List<T>, чтобы разработчикам приходилось вызывать ToList, иначе компилятор выдаст ошибку. Или ваш метод, который возвращает IEnumerable<DbDataReader>, должен возвращать List<DbDataReader>, где DbDataReader - это пользовательский интерфейс, реализованный всчитыватель данных из памяти, сгенерированный путем чтения данных из реального считывателя, поэтому вам не нужно беспокоиться о том, что считыватель остается открытым.

...