Ler a tabela SQL em C # DataTable

95

Eu li muitos posts sobre como inserir um DataTable em uma tabela SQL, mas existe uma maneira fácil de puxar uma tabela SQL para um .NET DataTable?

Vai
fonte
8
Umm ... usar o método Fill em um DataAdapter?
John Bledsoe

Respostas:

159

Aqui, experimente isto (este é apenas um pseudocódigo)

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
fonte
18
O datatablecampo deve ser inicializado antes da chamadada.Fill(dataTable)
Dabblernl
@ yonan2236 Que tal ter o parâmetro de saída de t sql ao lado da tabela de dados? como obter o parâmetro de saída também? É possível? Amostra?
Ahmad Ebrahimi
1
Este código está sujeito a erros e não é recomendável usar os recursos disponíveis desta forma. Por favor, veja a resposta de @Tim Rogers para a solução limpa.
Xan-Kun Clark-Davis
Além disso, dê uma olhada no LINQ (se ainda não o fez), pois ele pode realmente fazer alguma mágica aqui :-)
Xan-Kun Clark-Davis
Embora esse código funcione, ele não utiliza o try/catchou o using()para tratar o erro.
Si8 01 de
78
var table = new DataTable();    
using (var da = new SqlDataAdapter("SELECT * FROM mytable", "connection string"))
{      
    da.Fill(table);
}
Tim Rogers
fonte
7
@ Xan-KunClark-Davis: O código na resposta aceita vaza recursos se uma exceção for lançada. Você pode não desprezarusing tanto se compreender seu equivalente completo.
Ben Voigt
@ Xan-KunClark-Davis Por que você desprezaria Using?? Isso é como desprezar Withou Try-Catch. Eu sou o reverso; Fico desapontado quando não é suportado por uma classe.
SteveCinq de
12

De muitas maneiras.

Use ADO.Net e preencha o adaptador de dados para obter uma 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);
}

Você pode então obter a tabela de dados do conjunto de dados.

Nota no conjunto de dados de resposta votada não é usado, (apareceu após minha resposta)

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

O que é preferível ao meu.

Eu recomendaria fortemente olhar para a estrutura de entidade embora ... usar datatables e datasets não é uma boa ideia. Não há segurança de tipo neles, o que significa que a depuração só pode ser feita em tempo de execução. Com coleções fortemente tipadas (que você pode obter usando LINQ2SQL ou estrutura de entidade), sua vida será muito mais fácil.

Edit: Talvez eu não tenha sido claro: Datatables = good, datasets = evil. Se você estiver usando ADO.Net, poderá usar ambas as tecnologias (EF, linq2sql, dapper, nhibernate ou orm of the month), visto que geralmente ficam sobre ado.net. A vantagem que você obtém é que pode atualizar seu modelo com muito mais facilidade à medida que seu esquema muda, desde que você tenha o nível certo de abstração, aproveitando a geração de código.

O adaptador ado.net usa provedores que expõem as informações de tipo do banco de dados, por exemplo, por padrão, ele usa um provedor de servidor sql, você também pode conectar - por exemplo - o provedor de postgress devart e ainda obter acesso às informações de tipo que então permitem que você, conforme descrito acima, use sua orma de escolha (quase sem dor - existem algumas peculiaridades) - acredito que a Microsoft também oferece um provedor oracle. O propósito INTEIRO disso é abstrair da implementação do banco de dados, quando possível.

João nicholas
fonte
1
Conjuntos de dados digitados têm segurança de tipo e coleções fortemente tipadas, assim como EF. Mas esses são apenas para quando seu aplicativo está totalmente acoplado ao banco de dados. Se você está escrevendo uma ferramenta que precisa funcionar com muitos bancos de dados diferentes, a segurança de tipo é um desejo impossível.
Ross Presser,
1
Conjuntos de dados digitados em .net são uma criação horrível de xml loucura e desgraça. Eu nunca trabalhei em um lugar que está disposto a aceitar a sobrecarga de manter tudo isso para conjuntos de dados digitados em microsofts. Eu não acho que mesmo a Microsoft sugere que seja sensato hoje em dia. Quanto à segurança de tipos com vários bancos de dados, é claro que você pode obtê-la - a questão é que você a converta em uma coleção digitada o mais rápido possível e a transmita para restringir os problemas de tipo a um local específico. Orms ajudará com isso e funcionará perfeitamente bem com vários bancos de dados. Se você não gosta de EF, use algo mais leve como dapper.
John Nicholas
1
Você não me entendeu. Se você está escrevendo uma ferramenta de propósito geral que não tem ideia de que tipo de banco de dados vai se conectar, então a segurança de tipo é um desejo impossível.
Ross Presser
1
Sql é fornecido. Além disso, se você não sabe que tipo de banco de dados, então por que precisa ser um banco de dados? Qual seria a aplicação de tal ferramenta genérica? Se você precisar se conectar a bancos de dados que são realmente tão radicalmente diferentes, você abstrairá dele atrás de um padrão de repositório e, dentro dele, você precisaria de adaptadores de banco de dados especializados diferentes e, nesse ponto, você saberia sobre os detalhes. O fato é que o código de consumo tem expectativas de tipo -> afirmações de tipo no adaptador. Sua restrição significa que você não tem ideia sobre a linguagem do banco de dados e, portanto, não pode consultar.
John Nicholas
3
Suponha que você estivesse escrevendo um clone do SSMS.
Ross Presser
9

Versão independente do fornecedor, depende exclusivamente de interfaces ADO.NET; 2 maneiras:

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];
            }
        }
    }
}

Fiz alguns testes de desempenho e a segunda abordagem sempre superou a primeira.

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());

Read1parece melhor aos olhos, mas o adaptador de dados tem melhor desempenho (para não confundir que um banco de dados superou o outro, as consultas eram todas diferentes). A diferença entre os dois dependia da consulta. A razão pode ser que Loadvárias restrições sejam verificadas linha por linha da documentação ao adicionar linhas (é um método ativado DataTable) enquanto Fillestá em DataAdapters que foram projetados apenas para isso - criação rápida de DataTables.

Nawfal
fonte
3
Você precisa cercar DataTable.Load()com .BeginLoadData()e .EndLoadData()atingir a mesma velocidade que com DataSet.
Nikola Bogdanović de
1

Modelo centralizado: você pode usá-lo de qualquer lugar!

Você só precisa chamar Below Format de sua função para esta 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);

É isso aí. é um método perfeito.

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
fonte