SqlDataAdapter contre SqlDataReader

130

Quelles sont les différences entre l'utilisation de SqlDataAdapter et de SqlDataReader pour obtenir des données à partir d'une base de données?

Je regarde spécifiquement leurs avantages et leurs inconvénients ainsi que leurs performances en termes de vitesse et de mémoire.

Merci

ragoût
la source

Réponses:

193

SqlDataReader:

  • Maintient la connexion ouverte jusqu'à ce que vous ayez terminé (n'oubliez pas de la fermer!).
  • Ne peut généralement être répété qu'une seule fois
  • N'est pas aussi utile pour la mise à jour vers la base de données

D'autre part, il:

  • N'a qu'un seul enregistrement en mémoire à la fois plutôt qu'un jeu de résultats complet (cela peut être ÉNORME )
  • Est à peu près aussi rapide que possible pour cette itération
  • Vous permet de commencer le traitement des résultats plus tôt (une fois que le premier enregistrement est disponible). Pour certains types de requêtes, cela peut également être très important.

SqlDataAdapter / DataSet

  • Vous permet de fermer la connexion dès que le chargement des données est terminé, et peut même la fermer automatiquement pour vous
  • Tous les résultats sont disponibles en mémoire
  • Vous pouvez le parcourir autant de fois que vous le souhaitez, ou même rechercher un enregistrement spécifique par index
  • Possède des facultés intégrées pour la mise à jour de la base de données

Au prix de:

  • Utilisation de la mémoire beaucoup plus élevée
  • Vous attendez que toutes les données soient chargées avant de les utiliser

Donc, cela dépend vraiment de ce que vous faites, mais j'ai tendance à préférer un DataReader jusqu'à ce que j'aie besoin de quelque chose qui n'est pris en charge que par un ensemble de données. SqlDataReader est parfait pour le cas commun d'accès aux données de liaison à une grille en lecture seule.

Pour plus d'informations, consultez la documentation officielle de Microsoft .

Joël Coehoorn
la source
5
DataSet est une banque de données en mémoire, tandis que le lecteur de données n'est qu'un moyen de récupérer les données. Sur une note plus légère, vous pouvez exécuter des requêtes Linq sur DataSet, mais pas sur un datareader.
Partha Choudhury
En fait, avec un peu de code supplémentaire, vous pouvez certainement exécuter des requêtes linq (ou au moins une requête) sur un lecteur de données. Utilisez simplement un bloc d'itérateur pour renvoyer le DataReader converti en IDataRecord dans votre while (reader.Read())boucle.
Joel Coehoorn
7
Cette réponse est trompeuse. Si vous encapsulez vos objets SqlConnection et SqlDataReader avec des instructions "using" (comme vous devriez de toute façon, puisqu'ils sont IDisposables), la connexion sera fermée automatiquement. Et vous pouvez utiliser un DataSet avec un SqlDataReader: appelez simplement DataSet.Load (SqlDataReader).
RickNZ
4
@RickNZ Ne soyez pas trop rapide à faire confiance en utilisant des déclarations pour fermer les choses pour vous. Ils appellent la méthode Dispose () de l'objet, et non la méthode Close (), et j'ai rencontré au moins un cas où le Dispose n'a pas fermé l'objet pour moi. Il est toujours préférable d'inclure un appel explicite à la méthode close à l'intérieur du bloc using.
Cdaragorn
5
@Cdaragorn, les documents MSDN sont généralement assez clairs sur Close () vs Dispose (). Dans le cas de SqlConnection, par exemple, les documents disent que Close () et Dispose () sont fonctionnellement équivalents. Je n'ai aucune objection à appeler Close (), mais les appels à Dispose () devraient également être présents pour tous les IDisposables - et le moyen le plus propre de le faire est d'utiliser une instruction using. Dans les cas où vous savez que Dispose () n'appelle pas Close (), alors vous devriez appeler Close () dans un bloc finally si vous le pouvez, pas dans le bloc using (donc il est toujours appelé s'il y a une exception).
RickNZ
17

La réponse à cela peut être assez large.

Essentiellement, la différence majeure pour moi qui influence habituellement mes décisions sur l'utilisation est qu'avec un SQLDataReader, vous «diffusez» des données de la base de données. Avec un SQLDataAdapter, vous extrayez les données de la base de données dans un objet qui peut lui-même être interrogé davantage, ainsi que d'effectuer des opérations CRUD sur.

Évidemment, avec un flux de données, SQLDataReader est BEAUCOUP plus rapide, mais vous ne pouvez traiter qu'un seul enregistrement à la fois. Avec un SQLDataAdapter, vous disposez d'une collection complète des lignes correspondantes à votre requête à partir de la base de données pour travailler avec / passer par votre code.

AVERTISSEMENT: si vous utilisez un SQLDataReader, TOUJOURS, TOUJOURS, TOUJOURS assurez-vous que vous écrivez le code approprié pour fermer la connexion puisque vous maintenez la connexion ouverte avec SQLDataReader. Si vous ne le faites pas, ou une gestion correcte des erreurs pour fermer la connexion en cas d'erreur dans le traitement des résultats, votre application sera CRIPPLE avec des fuites de connexion.

Pardonnez mon VB, mais c'est la quantité minimale de code que vous devriez avoir lors de l'utilisation d'un SqlDataReader:

Using cn As New SqlConnection("..."), _
      cmd As New SqlCommand("...", cn)

    cn.Open()
    Using rdr As SqlDataReader = cmd.ExecuteReader()
        While rdr.Read()
            ''# ...
        End While
    End Using
End Using     

équivalent C #:

using (var cn = new SqlConnection("..."))
using (var cmd = new SqlCommand("..."))
{
    cn.Open();
    using(var rdr = cmd.ExecuteReader())
    {
        while(rdr.Read())
        {
            //...
        }
    }
}
Jaywon
la source
Si votre objectif est d'obtenir des données à l'aide d'une requête de sélection sur db et d'accéder uniquement à ces données à différentes lignes, accédez à la ligne rpevious, etc., vous pouvez utiliser SQLDatareader et le charger dans une table de données à l'aide de dtable.Load (rdr). Puis parcourez de haut en bas dans cette table de données. Vous pouvez utiliser cette méthode au lieu de DataAdapter ...
variable
14

Un SqlDataAdapter est généralement utilisé pour remplir un DataSet ou DataTable et vous aurez donc accès aux données une fois votre connexion fermée (accès déconnecté).

Le SqlDataReader est un curseur à avance rapide uniquement et connecté qui a tendance à être généralement plus rapide que le remplissage d'un DataSet / DataTable.

De plus, avec un SqlDataReader, vous traitez vos données un enregistrement à la fois et ne gardez aucune donnée en mémoire. Évidemment, avec un DataTable ou un DataSet, vous avez une surcharge d'allocation de mémoire.

Si vous n'avez pas besoin de conserver vos données en mémoire, donc pour le rendu uniquement, optez pour le SqlDataReader. Si vous souhaitez traiter vos données de manière déconnectée, choisissez le DataAdapter pour remplir un DataSet ou DataTable.

Wim Hollebrandse
la source
10

Utilisez un SqlDataAdapter lorsque vous souhaitez remplir un DataSet / DataTable en mémoire à partir de la base de données. Vous avez alors la possibilité de fermer / supprimer la connexion, de transmettre la table de données / l'ensemble en mémoire. Vous pouvez ensuite manipuler les données et les conserver dans la base de données à l'aide de l'adaptateur de données, en conjonction avec InsertCommand / UpdateCommand.

Utilisez un SqlDataReader lorsque vous souhaitez un accès rapide aux données à faible encombrement mémoire sans avoir besoin de flexibilité pour, par exemple, transmettre les données autour de votre logique métier. Ceci est plus optimal pour une récupération rapide et à faible utilisation de la mémoire de gros volumes de données car il ne charge pas toutes les données en mémoire en une seule fois - avec l'approche SqlDataAdapter, le DataSet / DataTable serait rempli avec toutes les données, donc si il y a beaucoup de lignes et de colonnes, qui nécessiteront beaucoup de mémoire.

AdaTheDev
la source
0

La fonction Fill utilise un DataReader en interne. Si votre considération est "Laquelle est la plus efficace?", Alors l'utilisation d'un DataReader dans une boucle serrée qui remplit une collection enregistrement par enregistrement, est susceptible d'être la même charge sur le système que l'utilisation de DataAdapter.Fill.

(System.Data.dll, System.Data.Common.DbDataAdapter, FillInternal.)

billpg
la source