DataAdapter: можно ли заполнить Collection-Type вместо DataTable / DataSet?

это скорее теоретический вопрос, который я себе задавал. Я вспомнил, что BinarySearch упорядоченного списка (Коллекция в целом ) быстрее, чем поиск строк с помощью Datatable.Rows.Find или DataTable.FindByPK со значением первичного ключа.

Следовательно, я заполняю Datatable из базы данных в общем конструкторе и сразу после этого List (of Int32), который содержит все первичные ключи из этой таблицы. Позже я проверю с помощью BinarySearch, содержит ли список значения первичного ключа. Но поскольку datatable в любом случае содержит только PK-Column, я спросил себя, есть ли способ избежать огромных накладных расходов на заполнение Datatable и после этого добавления всех строк в список. Можно ли заполнить общий список (или другой тип коллекции) вместо Datatable / Dataset непосредственно из Dataadapter? Может быть, я сбился с пути, и есть другой способ избежать лишнего зацикливания, которого мне не хватает.

Код заполнения DataTable в строго типизированном наборе данных и списке:

   Private Shared w205CorrectSWUpgrades As New List(Of Int32)

   Shared Sub New()
        Dim da As New dsDatabaseTableAdapters.W205SWUpgradesTableAdapter
        For Each row As dsDatabase.W205SWUpgradesRow In da.Get_W205CorrectSWUpgrades.Rows
           w205CorrectSWUpgrades.Add(row.idData)
        Next
    End Sub

ОБНОВЛЕНИЕ. Для полноты картины мое решение (спасибо TheCloudlessSky): поскольку DataAdapter сам использует DataReader для заполнения Datatable или Dataset, лучшим способом было расширить сгенерированный (из VS) частичный класс DataAdapter с новой функцией, которая возвращает список (из Int32), заполненный непосредственно из базы данных. Помните, что этот частичный класс должен находиться в другом файле, чем сгенерированный класс, иначе ваш исходный код будет перезаписан при изменениях в наборе данных. Также помните, что он должен находиться в том же пространстве имен (оканчивается адаптерами таблиц) и, конечно же, иметь то же имя.

 Namespace dsDatabaseTableAdapters
    Partial Public Class W205SWUpgradesTableAdapter

        Public Function GetListOfW205CorrectSWUpgrades() As System.Collections.Generic.List(Of System.Int32)
            Dim list As New System.Collections.Generic.List(Of System.Int32)
            Dim command As System.Data.SqlClient.SqlCommand = Me.CommandCollection(0)   

            Dim previousConnectionState As System.Data.ConnectionState = command.Connection.State
            Try
               If ((command.Connection.State And Global.System.Data.ConnectionState.Open) _
                        <> Global.System.Data.ConnectionState.Open) Then
                   command.Connection.Open()
               End If
               Using reader As System.Data.SqlClient.SqlDataReader = command.ExecuteReader
                   While reader.Read
                      list.Add(reader.GetInt32(0))
                   End While
               End Using
            Finally
                If (previousConnectionState = System.Data.ConnectionState.Closed) Then
                    command.Connection.Close()
                End If
            End Try

            Return list
        End Function

    End Class
End Namespace

Теперь бизнес-логика и уровень доступа к данным по-прежнему строго разделены (в отдельных проектах):

    Private Shared w205CorrectSWUpgrades As List(Of Int32)

    Shared Sub New()
        Dim da As New dsDatabaseTableAdapters.W205SWUpgradesTableAdapter
        w205CorrectSWUpgrades = da.GetListOfW205CorrectSWUpgrades
    End Sub

person Tim Schmelter    schedule 04.08.2010    source источник


Ответы (1)


Почему бы вам не использовать вместо этого DataReader, поскольку это довольно тривиально? В C # вы бы сделали следующее:

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

using (SqlConnection conn = new SqlConnection("your connection string"))
{
    SqlCommand command = new SqlCommand("SELECT Id FROM Table", conn);

    using (SqlDataReader reader = command.ExecuteReader())
    {
        // Loop through each record.
        while (reader.Read())
        {
            primaryKeys.Add(reader.GetInt32(0));
        }
    }
}   
person TheCloudlessSky    schedule 04.08.2010
comment
Это то, о чем я сначала подумал, и это был бы ответ. Но большим недостатком DataReader является то, что вам нужно активное соединение с базой данных во время итерации по строкам. Это было бы узким местом, поскольку мой вопрос нацелен на большой объем данных. Но +1, все равно спасибо - person Tim Schmelter; 04.08.2010
comment
С другой стороны, я думаю, что это единственный ответ в Ado.Net, не так ли? Другой недостаток заключается в том, что я не мог использовать свой строго типизированный набор данных с Datareader. - person Tim Schmelter; 04.08.2010
comment
@Tim - Конечно, вам нужно живое соединение при просмотре результатов. DataReader - это то, что DataAdapter использует для получения своих данных. ADO.NET - термин для доступа к данным с помощью .NET, и DataReader является его частью. Это то, что используют все другие классы доступа к данным для чтения из источника данных, такого как SQL. Вам не нужен строго типизированный набор данных, потому что возвращаются только int. - person TheCloudlessSky; 04.08.2010
comment
@TheCloudlessSky: Я думал, что DataAdapter будет заполнять Datatable / набор данных иначе, чем при использовании Datareader, но в следующей статье подчеркивается ваше утверждение: msdn.microsoft.com/en-us/magazine/cc188717.aspx - person Tim Schmelter; 04.08.2010
comment
Хорошо, в качестве ответа я беру твое устройство чтения данных. Но, к сожалению, тогда я смешиваю бизнес-логику с уровнем доступа к данным. - person Tim Schmelter; 04.08.2010
comment
Я решил эту проблему с помощью этой ссылки: simple-talk.com/dotnet/.net-framework/ - person Tim Schmelter; 04.08.2010
comment
@ Тим - Рад, что у тебя сработало. Вам также следует изучить возможность использования ORM, например Entity Framework или NHibernate. Ваше здоровье! - person TheCloudlessSky; 04.08.2010