2016-03-14 4 views
1

При взгляде на примеры в Интернете о том, как использовать SqlDataReader я нашел такие вещи, как:Преобразовать SqlDataReader к выражению Linq

var command = new SqlCommand( // initialize with query and connection... 
var reader = command.ExecuteReader(); 

while(reader.Read()) 
{ 
    var foo = reader["SomeColName"]; 
    // etc 
} 

Могу ли я использовать следующий метод расширения:

public static IEnumerable<IDataReader> ToEnumerable(this IDataReader reader) 
{ 
    while (reader.Read())    
     yield return reader;    
} 

Для того, чтобы выполнять запросы с помощью linq?

Если я использую следующий метод расширения, это будет плохо? Если мне нужна производительность, я должен использовать первую реализацию?

+0

Я думаю, что работа не будет проблемой здесь, его просто генерируя состояние-машины для выхода. Помимо этого я бы рекомендовал выставлять 'IDataRecord' вместо' IDataReader' (наследование), иначе вы бы разоблачили 'Read'-method (чтобы пользователи могли вызвать этот метод и испортить набор результатов). – Caramiriel

ответ

1

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

Я не уверен, есть ли хороший способ совместить IDataReader с LINQ, но вы можете что-то вроде этого:

public static IEnumerable<Dictionary<string, object>> ToEnumerable(this IDataReader reader) 
{ 
    while (reader.Read()) 
    { 
     Dictionary<string, object> result = new Dictionary<string, object>(); 
     for (int column = 0; column < reader.FieldCount; column++) 
      result.Add(reader.GetName(column), reader.GetValue(column)); 
     yield return result; 
    } 
} 

Это возвращает последовательность словарей (один словарь для каждой строки), который сопоставьте имя столбца с объектом в этой ячейке.

К несчастью, вы теряете безопасность типов и создаете накладные расходы памяти. Конкретная реализация по-прежнему будет зависеть от того, чего вы действительно хотите достичь. Лично я всегда использую только индекс столбца вместо имени.


То есть, я думаю, что лучший подход по-прежнему использовать IDataReader непосредственно для создания Pocos и использовать это Pocos с LINQ:

IEnumerable<string> GetSomeColValue(IDataReader reader) 
{ 
    while(reader.Read()) 
     yield return reader.GetString(reader.GetOrdinal("SomeColName")); 
} 

Конечно, это сокращенный пример. В реальном коде я полностью считывал все данные из читателя и закрывал/удалял экземпляр читателя внутри метода, который вызывал ExecuteReader, прежде чем что-либо вернуть.

5

Вам просто нужно, чтобы бросить ваш IEnumerable в IEnumerable<IDataRecord>

var enumerable = reader.Cast<IDataRecord>(); 
var col = enumerable.Select(record => record .GetOrdinal("SomeColName")); 
+0

Мне любопытно, где это расширение 'Cast' для' IDataReader' объявлено? 'IDataReader' даже не объявляет метод GetEnumerator. –

+0

(Sql | Db) DataReader реализует IEnumerable. И Cast - это метод расширения, определенный в System.Linq.Enumerable. – Kalten

+0

Да, интересно, 'SqlDataReader' тоже реализует это. Никогда не использовал его, и MSDN не ясно говорит, является ли это перечислителем для столбцов текущей строки или если это повторяется через строки. Я посмотрю на него и, возможно, буду использовать его в будущем (хотя msdn утверждает, что цикл предпочтительнее, но не почему). –

 Смежные вопросы

  • Нет связанных вопросов^_^