Lire la table SQL dans C # DataTable

93

J'ai lu de nombreux articles sur l'insertion d'un DataTable dans une table SQL, mais existe-t-il un moyen simple d'extraire une table SQL dans un DataTable .NET?

Volonté
la source
8
Umm ... utiliser la méthode Fill sur un DataAdapter?
John Bledsoe

Réponses:

156

Ici, donnez-moi une chance (ce n'est qu'un pseudocode)

using System;
using System.Data;
using System.Data.SqlClient;


public class PullDataTest
{
    // your data table
    private DataTable dataTable = new DataTable();

    public PullDataTest()
    {
    }

    // your method to pull data from database to datatable   
    public void PullData()
    {
        string connString = @"your connection string here";
        string query = "select * from table";

        SqlConnection conn = new SqlConnection(connString);        
        SqlCommand cmd = new SqlCommand(query, conn);
        conn.Open();

        // create data adapter
        SqlDataAdapter da = new SqlDataAdapter(cmd);
        // this will query your database and return the result to your datatable
        da.Fill(dataTable);
        conn.Close();
        da.Dispose();
    }
}
yonan2236
la source
18
Le datatablechamp doit être initialisé avant d'appelerda.Fill(dataTable)
Dabblernl
@ yonan2236 Que diriez-vous d'avoir des paramètres de sortie de t sql à côté de datatable? comment obtenir les paramètres de sortie aussi? C'est possible? Échantillon?
Ahmad Ebrahimi
1
Ce code est sujet aux erreurs et il n'est pas recommandé d'utiliser les ressources disponibles de cette façon. Veuillez consulter la réponse @Tim Rogers pour la solution propre.
Xan-Kun Clark-Davis
En dehors de cela, jetez un œil à LINQ (si ce n'est déjà fait) car il peut vraiment faire de la magie ici :-)
Xan-Kun Clark-Davis
78
var table = new DataTable();    
using (var da = new SqlDataAdapter("SELECT * FROM mytable", "connection string"))
{      
    da.Fill(table);
}
Tim Rogers
la source
7
@ Xan-KunClark-Davis: Le code de la réponse acceptée laisse échapper des ressources si une exception est levée. Vous pourriez ne pas mépriser usingautant si vous compreniez son équivalent complet.
Ben Voigt
@ Xan-KunClark-Davis Pourquoi méprisez-vous Using?? C'est comme mépriser Withou Try-Catch. Je suis l'inverse; Je suis déçu quand il n'est pas pris en charge par une classe.
SteveCinq
12

Beaucoup de façons.

Utilisez ADO.Net et utilisez fill sur l'adaptateur de données pour obtenir un DataTable:

using (SqlDataAdapter dataAdapter
    = new SqlDataAdapter ("SELECT blah FROM blahblah ", sqlConn))
{
    // create the DataSet 
    DataSet dataSet = new DataSet(); 
    // fill the DataSet using our DataAdapter 
    dataAdapter.Fill (dataSet);
}

Vous pouvez ensuite extraire la table de données de l'ensemble de données.

La note dans l'ensemble de données de réponse avec vote positif n'est pas utilisée, (elle est apparue après ma réponse)

// create data adapter
SqlDataAdapter da = new SqlDataAdapter(cmd);
// this will query your database and return the result to your datatable
da.Fill(dataTable);

Ce qui est préférable au mien.

Je recommanderais fortement de regarder le cadre d'entité cependant ... utiliser des tables de données et des ensembles de données n'est pas une bonne idée. Il n'y a pas de sécurité de type sur eux, ce qui signifie que le débogage ne peut être effectué qu'au moment de l'exécution. Avec des collections fortement typées (que vous pouvez obtenir en utilisant LINQ2SQL ou un framework d'entité), votre vie sera beaucoup plus facile.

Edit: Peut-être que je n'étais pas clair: Datatables = good, datasets = evil. Si vous utilisez ADO.Net, vous pouvez utiliser ces deux technologies (EF, linq2sql, dapper, nhibernate, orm du mois) car elles se trouvent généralement au-dessus de ado.net. L'avantage que vous obtenez est que vous pouvez mettre à jour votre modèle beaucoup plus facilement à mesure que votre schéma change, à condition que vous ayez le bon niveau d'abstraction en exploitant la génération de code.

L'adaptateur ado.net utilise des fournisseurs qui exposent les informations de type de la base de données, par exemple, par défaut, il utilise un fournisseur de serveur SQL, vous pouvez également brancher - par exemple - le fournisseur devart postgress et toujours avoir accès aux informations de type qui seront ensuite vous permettre comme ci-dessus d'utiliser votre orm de choix (presque sans douleur - il y a quelques bizarreries) - je crois que Microsoft fournit également un fournisseur d'oracle. Le but ENTIER de ceci est d'abstraire de l'implémentation de la base de données lorsque cela est possible.

John Nicholas
la source
1
Les ensembles de données typés ont une sécurité de type et des collections fortement typées, tout comme EF. Mais ce n'est que lorsque votre application est étroitement couplée à la base de données. Si vous écrivez un outil qui doit fonctionner avec de nombreuses bases de données différentes, la sécurité des types est un souhait désespéré.
Ross Presser
1
Les ensembles de données typés dans .net sont une horrible création de folie et de malheur xml. Je n'ai jamais travaillé dans un endroit qui est prêt à accepter la surcharge de maintenir tout cela pour des ensembles de données typés microsofts. Je ne pense pas que même Microsoft suggère son sens ces jours-ci. En ce qui concerne la sécurité de type avec plusieurs bases de données, bien sûr, vous pouvez l'obtenir - le fait est que vous la convertissez en collection typée dès que possible et que vous la transmettez afin de limiter les problèmes de type à un endroit spécifique. Orms aidera avec cela et fonctionnera parfaitement bien avec plusieurs bases de données. Si vous n'aimez pas EF, utilisez quelque chose de plus léger comme pimpant.
John Nicholas
1
Vous ne m'avez pas compris. Si vous écrivez un outil à usage général qui n'a aucune idée du type de base de données auquel il va se connecter, alors la sécurité de type est un souhait désespéré.
Ross Presser
1
Sql est donné. En outre, si vous ne savez pas quel type de base de données, pourquoi doit-il même être une base de données? Quelle serait l'application d'un tel outil générique? Si jamais vous avez besoin de vous connecter à des bases de données qui sont vraiment si radicalement différentes, vous en feriez abstraction derrière un modèle de référentiel, puis à l'intérieur de cela, vous auriez besoin de différents adaptateurs de base de données spécialisés et à ce moment-là, vous en connaîtrez les détails. Le fait de consommer du code a des attentes de type -> assertions de type dans l'adaptateur. Votre contrainte signifie que vous n'avez aucune idée de la langue de la base de données et que vous ne pouvez donc pas interroger.
John Nicholas
3
Supposons que vous écriviez un clone SSMS?
Ross Presser
9

Version indépendante du fournisseur, repose uniquement sur les interfaces ADO.NET; 2 façons:

public DataTable Read1<T>(string query) where T : IDbConnection, new()
{
    using (var conn = new T())
    {
        using (var cmd = conn.CreateCommand())
        {
            cmd.CommandText = query;
            cmd.Connection.ConnectionString = _connectionString;
            cmd.Connection.Open();
            var table = new DataTable();
            table.Load(cmd.ExecuteReader());
            return table;
        }
    }
}

public DataTable Read2<S, T>(string query) where S : IDbConnection, new() 
                                           where T : IDbDataAdapter, IDisposable, new()
{
    using (var conn = new S())
    {
        using (var da = new T())
        {
            using (da.SelectCommand = conn.CreateCommand())
            {
                da.SelectCommand.CommandText = query;
                da.SelectCommand.Connection.ConnectionString = _connectionString;
                DataSet ds = new DataSet(); //conn is opened by dataadapter
                da.Fill(ds);
                return ds.Tables[0];
            }
        }
    }
}

J'ai fait quelques tests de performance, et la deuxième approche a toujours surpassé la première.

Stopwatch sw = Stopwatch.StartNew();
DataTable dt = null;
for (int i = 0; i < 100; i++)
{
    dt = Read1<MySqlConnection>(query); // ~9800ms
    dt = Read2<MySqlConnection, MySqlDataAdapter>(query); // ~2300ms

    dt = Read1<SQLiteConnection>(query); // ~4000ms
    dt = Read2<SQLiteConnection, SQLiteDataAdapter>(query); // ~2000ms

    dt = Read1<SqlCeConnection>(query); // ~5700ms
    dt = Read2<SqlCeConnection, SqlCeDataAdapter>(query); // ~5700ms

    dt = Read1<SqlConnection>(query); // ~850ms
    dt = Read2<SqlConnection, SqlDataAdapter>(query); // ~600ms

    dt = Read1<VistaDBConnection>(query); // ~3900ms
    dt = Read2<VistaDBConnection, VistaDBDataAdapter>(query); // ~3700ms
}
sw.Stop();
MessageBox.Show(sw.Elapsed.TotalMilliseconds.ToString());

Read1semble mieux aux yeux, mais l'adaptateur de données fonctionne mieux (ne pas confondre le fait qu'une base de données a surpassé l'autre, les requêtes étaient toutes différentes). La différence entre les deux dépendait cependant de la requête. La raison pourrait être que Loaddiverses contraintes doivent être vérifiées ligne par ligne à partir de la documentation lors de l'ajout de lignes (c'est une méthode activée DataTable) alors que Fillc'est sur DataAdapters qui ont été conçus juste pour cela - création rapide de DataTables.

nawfal
la source
3
Vous devez entourer le DataTable.Load()avec .BeginLoadData()et .EndLoadData()pour atteindre la même vitesse qu'avec le DataSet.
Nikola Bogdanović
1

Modèle centré: vous pouvez l'utiliser de n'importe où!

Il vous suffit d'appeler below Format De votre fonction à cette classe

DataSet ds = new DataSet();
SqlParameter[] p = new SqlParameter[1];
string Query = "Describe Query Information/either sp, text or TableDirect";
DbConnectionHelper dbh = new DbConnectionHelper ();
ds = dbh. DBConnection("Here you use your Table Name", p , string Query, CommandType.StoredProcedure);

C'est ça. c'est une méthode parfaite.

public class DbConnectionHelper {
   public DataSet DBConnection(string TableName, SqlParameter[] p, string Query, CommandType cmdText) {
    string connString = @ "your connection string here";
    //Object Declaration
    DataSet ds = new DataSet();
    SqlConnection con = new SqlConnection();
    SqlCommand cmd = new SqlCommand();
    SqlDataAdapter sda = new SqlDataAdapter();
    try {
     //Get Connection string and Make Connection
     con.ConnectionString = connString; //Get the Connection String
     if (con.State == ConnectionState.Closed) {
      con.Open(); //Connection Open
     }
     if (cmdText == CommandType.StoredProcedure) //Type : Stored Procedure
     {
      cmd.CommandType = CommandType.StoredProcedure;
      cmd.CommandText = Query;
      if (p.Length > 0) // If Any parameter is there means, we need to add.
      {
       for (int i = 0; i < p.Length; i++) {
        cmd.Parameters.Add(p[i]);
       }
      }
     }
     if (cmdText == CommandType.Text) // Type : Text
     {
      cmd.CommandType = CommandType.Text;
      cmd.CommandText = Query;
     }
     if (cmdText == CommandType.TableDirect) //Type: Table Direct
     {
      cmd.CommandType = CommandType.Text;
      cmd.CommandText = Query;
     }
     cmd.Connection = con; //Get Connection in Command
     sda.SelectCommand = cmd; // Select Command From Command to SqlDataAdaptor
     sda.Fill(ds, TableName); // Execute Query and Get Result into DataSet
     con.Close(); //Connection Close
    } catch (Exception ex) {

     throw ex; //Here you need to handle Exception
    }
    return ds;
   }
  }
Elango Sengottaiyan
la source