Czytaj tabelę SQL w C # DataTable


Odpowiedzi:


156

Tutaj, daj temu szansę (to tylko pseudokod)

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

18
datatablePole musi zostać zainicjowane przed wywołaniemda.Fill(dataTable)
Dabblernl

@ yonan2236 A co z parametrem wyjściowym z t sql obok datatable? jak uzyskać parametr wyjściowy też? Czy to możliwe? Próba?
Ahmad Ebrahimi

1
Ten kod jest podatny na błędy i nie zaleca się korzystania w ten sposób z dostępnych zasobów. Zobacz odpowiedź @Tim Rogers, aby uzyskać czyste rozwiązanie.
Xan-Kun Clark-Davis

Poza tym spójrz na LINQ (jeśli jeszcze tego nie zrobiłeś), ponieważ tutaj naprawdę może zdziałać magię :-)
Xan-Kun Clark-Davis

78
var table = new DataTable();    
using (var da = new SqlDataAdapter("SELECT * FROM mytable", "connection string"))
{      
    da.Fill(table);
}

7
@ Xan-KunClark-Davis: Kod w zaakceptowanej odpowiedzi przecieka zasoby, jeśli zostanie zgłoszony wyjątek. Możesz nie gardzić usingtak bardzo, jeśli rozumiesz jego pełny odpowiednik.
Ben Voigt

@ Xan-KunClark-Davis Dlaczego miałbyś pogardzać Using?? To jak pogardzanie Withlub Try-Catch. Ja jestem odwrotnie; Jestem rozczarowany, gdy nie jest obsługiwany przez klasę.
SteveCinq

12

Wiele sposobów.

Użyj ADO.Net i użyj wypełnienia adaptera danych, aby uzyskać 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);
}

Następnie możesz pobrać tabelę danych ze zbioru danych.

Uwaga w zbiorze danych dotyczących odpowiedzi za pozytywnymi odpowiedziami nie jest używany (pojawiło się po mojej odpowiedzi)

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

Co jest lepsze od mojego.

Zdecydowanie zalecałbym jednak przyjrzenie się strukturze encji ... używanie danych i zestawów danych nie jest dobrym pomysłem. Nie ma na nich żadnego zabezpieczenia typów, co oznacza, że ​​debugowanie można przeprowadzić tylko w czasie wykonywania. Dzięki kolekcjom silnie wpisanym (które można uzyskać za pomocą LINQ2SQL lub frameworku jednostek) Twoje życie będzie o wiele łatwiejsze.

Edycja: Być może nie było jasne: dane = dobre, zbiory danych = zło. Jeśli używasz ADO.Net, możesz użyć obu tych technologii (EF, linq2sql, dapper, nhibernate, orm of the month), ponieważ zazwyczaj znajdują się one na szczycie ado.net. Zaletą jest to, że możesz znacznie łatwiej zaktualizować model, gdy zmieni się schemat, pod warunkiem, że masz odpowiedni poziom abstrakcji, wykorzystując generowanie kodu.

Adapter ado.net korzysta z dostawców, którzy ujawniają informacje o typie bazy danych, na przykład domyślnie korzysta z dostawcy serwera sql, możesz również podłączyć - na przykład - dostawcę postgress devart i nadal uzyskać dostęp do informacji o typie, które następnie pozwalają ci jak wyżej korzystać z twojego wyboru (prawie bezboleśnie - jest kilka dziwactw) - uważam, że Microsoft również zapewnia dostawcę Oracle. CAŁKOWITYM celem tego jest oderwanie się od implementacji bazy danych tam, gdzie to możliwe.


1
Typowane zestawy danych mają bezpieczeństwo typów i kolekcje silnie wpisane, podobnie jak EF. Ale to tylko wtedy, gdy Twoja aplikacja jest ściśle powiązana z bazą danych. Jeśli piszesz narzędzie, które ma współpracować z wieloma różnymi bazami danych, bezpieczeństwo typów jest beznadziejnym życzeniem.
Ross Presser

1
Wpisane zbiory danych w .net są okropnym dziełem szaleństwa i niedoli XML. Nigdy nie pracowałem w miejscu, które jest skłonne zaakceptować narzut związany z utrzymaniem tego wszystkiego dla zestawów danych wpisanych w mikrosoftach. Nie sądzę, żeby nawet Microsoft sugerował, że jest to rozsądne w dzisiejszych czasach. Jeśli chodzi o bezpieczeństwo typów z wieloma bazami danych, oczywiście możesz to uzyskać - chodzi o to, że konwertujesz je na kolekcję wpisaną jak najszybciej i przekazujesz to, aby ograniczyć problemy z typami do określonego miejsca. Orms pomoże w tym i doskonale współpracuje z wieloma bazami danych. Jeśli nie lubisz EF, użyj czegoś lżejszego, na przykład eleganckiego.
John Nicholas

1
Nie zrozumiałeś mnie. Jeśli piszesz narzędzie ogólnego przeznaczenia, które nie ma pojęcia, z jaką bazą danych będzie się łączyć, bezpieczeństwo typów jest beznadziejnym życzeniem.
Ross Presser,

1
Sql jest podane. Poza tym, jeśli nie wiesz, jaki rodzaj bazy danych, dlaczego w ogóle musi to być baza danych? Jakie byłoby zastosowanie takiego ogólnego narzędzia? Jeśli kiedykolwiek będziesz musiał połączyć się z bazami danych, które są naprawdę tak radykalnie różne, odejdziesz od nich za wzorcem repozytorium, a następnie będziesz potrzebować różnych wyspecjalizowanych adapterów bazy danych i wtedy będziesz wiedział o szczegółach. Faktem jest, że kod konsumujący ma oczekiwania typu -> potwierdzenia typu w adapterze. Twoje ograniczenie oznacza, że ​​nie masz pojęcia o języku bazy danych i nie możesz wykonywać zapytań.
John Nicholas

3
Załóżmy, że piszesz klon SSMS?
Ross Presser

9

Wersja niezależna od dostawcy, oparta wyłącznie na interfejsach ADO.NET; 2 drogi:

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

Zrobiłem kilka testów wydajności i drugie podejście zawsze było lepsze od pierwszego.

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

Read1wygląda lepiej na oczach, ale adapter danych działa lepiej (aby nie mylić, że jedna baza danych przewyższa drugą, zapytania były różne). Różnica między nimi zależała jednak od zapytania. Powodem może być to, że podczas dodawania wierszy Loadwymagane jest sprawdzanie różnych ograniczeń wiersz po wierszu z dokumentacji podczas dodawania wierszy (jest to metoda włączona DataTable), podczas gdy Filljest to na adapterach DataAdapters, które zostały zaprojektowane specjalnie do tego celu - szybkie tworzenie DataTables.


3
Musisz otoczyć DataTable.Load()z .BeginLoadData()i .EndLoadData()osiągnąć taką samą prędkość jak w przypadku DataSet.
Nikola Bogdanović

1

Model centralny: możesz go używać z dowolnego miejsca!

Wystarczy wywołać funkcję Below Format From do tej klasy

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

Otóż ​​to. to doskonała metoda.

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;
   }
  }
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.