Подтвердить что ты не робот

Заполните массив (или arraylist) из SqlDataReader

Есть ли способ заполнить массив с помощью SqlDataReader (или любого другого объекта С# ADO.NET) без перебора всех элементов? У меня есть запрос, возвращающий один столбец, и я хочу поместить его в массив строк (или ArrayList, или List и т.д.).

4b9b3361

Ответ 1

Это возможно. В .NET 2.0+ SqlDataReader наследуется от DbDataReader, который реализует IEnumerable (не общий). Это означает, что вы можете использовать LINQ:

List<string> list = (from IDataRecord r in dataReader
                     select (string)r["FieldName"]
                    ).ToList();

Тем не менее, цикл все еще существует, он просто скрыт в Enumerable.Select, а не является явным в вашем коде.

Ответ 2

Нет, поскольку SqlDataReader - это поток строк только для чтения из базы данных SQL Server, доступный только для чтения, поток строк будет зациклирован на то, явно ли он в вашем коде или скрыт в реализации фреймворка (например, DataTable Load).

Похоже, что использовать общий список, а затем вернуть список в качестве массива будет хорошим вариантом. Например,

List<int> list = new List<int>();

using (SqlDataReader reader = cmd.ExecuteReader())
{
    while (reader.Read())
    {
         list.Add(reader.GetInt32(0));
    }    
}
return list.ToArray();

В ответ на ваш комментарий вызов ToArray() может быть накладным, это зависит. Вам нужен массив объектов для работы с общей коллекцией (например, List<T> или ReadOnlyCollection<T>)?

Ответ 3

Так как любая реализация IDataReader (SqlDataReader включена) будет по определению прямым читателем, нет никакого способа сделать это без цикла. Даже если бы для этого был метод библиотеки баз данных, ему пришлось бы прорезать читателя так же, как и вы.

Ответ 4

По-видимому, с тех пор как .NET 1.1 SqlDataReader имел следующий метод:

int size;
object[] data = new object[]{};
size = reader.GetValues(data);

Это заполняет data значениями текущей строки считывателя, присваивая размер числу объектов, помещенных в массив.

Ответ 5

Если вы прочитали свой SqlDataAdapter в DataTable:

DataTable dt as DataTable; 
dt.fill(data);

Затем вы можете использовать некоторые из игрушек в System.Data.DataSetExtensions, как указано в Joel Muller, на этот вопрос .

В использует бит Linq, так что вы будете чистым .Net 3.5 или выше.

Ответ 6

Orignial OP запросил Array, ArrayList или List. Вы также можете вернуть массив. Просто вызовите метод .ToArray() и назначьте его ранее объявленному массиву. Массивы очень быстры, когда дело доходит до перечисления каждого элемента. Гораздо быстрее, чем список, если список содержит более 1000 элементов. Вы можете вернуться к массиву, списку или словарю.

ids_array = (from IDataRecord r in idReader 
select (string)r["ID"]).ToArray<string>();  

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

 HashSet<string> hs = new HashSet<string>( 
(from IDataRecord r in idReader select (string)r["ID"]).AsEnumerable<string>() );

Ответ 7

Вам нужно выполнить цикл, но есть проекты, которые могут сделать его более простым. Также попробуйте не использовать ArrayList, вместо этого используйте List.

Вы можете проверить FluentAdo для одного: http://fluentado.codeplex.com

    public IList<UserAccount> List()
    {
        var list = new FluentCommand<UserAccount>("SELECT ID, UserName, Password FROM UserAccount")
            .SetMap(reader => new UserAccount
            {
                ID = reader.GetInt("ID"),
                Password = reader.GetString("Password"),
                UserName = reader.GetString("UserName"),
            })
            .AsList();

        return list;
    }