18

I have a simple .Net Framework routine which runs a query and returns a DataTable object. I need to port this to .Net Core, however I infer that SQLAdapter and DataTable are not supported

SqlConnection con = new SqlConnection(m_ConnectString);
SqlCommand cmd = new SqlCommand(strQuery);
SqlDataAdapter sda = new SqlDataAdapter();
// assign the transaction and connection to the command object
cmd.Connection = con;
sda.SelectCommand = cmd;
DataTable dt = new DataTable();
// execute query and soak up results
sda.Fill(dt);
return dt;

Can anyone suggest how I can reimplement this code, using what is supported ? Thanks

Bernard Vander Beken
  • 4,848
  • 5
  • 54
  • 76
Hughgo
  • 1,319
  • 5
  • 17
  • 26
  • Well, you could start by looking at the reference source for [SqlDataAdapter](http://referencesource.microsoft.com/#System.Data/System/Data/SqlClient/SqlDataAdapter.cs) and [DataTable](http://referencesource.microsoft.com/#System.Data/System/Data/DataTable.cs) and reimplement the parts you actually need... also: good luck. – Corak Jul 27 '16 at 08:52
  • Thanks for replying, but not sure how helpful that is. I had assumed that many others would have hit this problem, and that they are not all setting out to fix it by implementing parts of the Framework. – Hughgo Jul 27 '16 at 09:17
  • 2
    Well, one problem is that if .Net Core does not know about `DataTable`, then you can't `return dt` and everything else that would work with the `DataTable` won't work anymore. So the question is, what functionality of the `DataTable` do you really need, and can you use for example a `DataReader` for that instead (if `DataReader` is available in .Net Core; never worked with that). – Corak Jul 27 '16 at 09:22
  • use either entityframework or dapper. for this – Sujit.Warrier Jul 27 '16 at 09:39
  • @Sujit.Warrier How can I get untyped query results from Dapper? – ProfK Jul 12 '17 at 05:25

4 Answers4

23

SqlDBAdapter and DataTable are now supported.

You must use VS2017 Preview 15.3, target .net core 2.0, and add NuGet packages for System.Data.Common as well as System.Data.SqlClient. Code below.

See https://blogs.msdn.microsoft.com/devfish/2017/05/15/exploring-datatable-and-sqldbadapter-in-asp-net-core-2-0/ for more info.

public static DataTable ExecuteDataTable(SqlConnection conn, CommandType cmdType, string cmdText, SqlParameter[] cmdParms)
{
    DataTable dt = new DataTable();
    dt.Columns.Add("CustomerID");
    dt.Columns.Add("CustomerName");
    SqlDataReader dr = ExecuteReader(conn, cmdType, cmdText, cmdParms);
    while (dr.Read())
    {
        dt.Rows.Add(dr[0], dr[1]);
    }
    return dt;
}

public static DataTable ExecuteDataTableSqlDA(SqlConnection conn, CommandType cmdType, string cmdText, SqlParameter[] cmdParms)
{
    System.Data.DataTable dt = new DataTable();
    System.Data.SqlClient.SqlDataAdapter da = new SqlDataAdapter(cmdText, conn);
    da.Fill(dt);
    return dt;
}
Quality Catalyst
  • 6,531
  • 8
  • 38
  • 62
Joe Healy
  • 5,769
  • 3
  • 38
  • 56
  • I haven't used VS2017 Preview 15.3 yet so I was unaware of this development. – Fabulous Jul 11 '17 at 22:20
  • happy that this helped you out. – Joe Healy Jul 13 '17 at 13:26
  • As of VS2017 Preview 15.4 this still requires the prerelease version of `System.Data.SqlClient` – djoyce Jul 19 '17 at 08:38
  • Hi is there a way to do this with oracle DB ? – Mlle 116 Mar 29 '18 at 07:25
  • re oracle .NET Core and Entity Framework Statement of Direction - March 2018 - www.oracle.com/technetwork/topics/dotnet/tech-info/odpnet-dotnet-ef-core-sod-4395108.pdf ODP.NET Core Beta Download - http://www.oracle.com/technetwork/topics/dotnet/downloads/odpnetcorebeta-4077982.html ODP.NET Discussion Forum - https://community.oracle.com/community/database/developer-tools/windows_and_.net/odp.net – Joe Healy Mar 30 '18 at 13:25
9

UPDATE: This answer corresponds to .NET Core 1.x (which was the latest at the time I wrote this). If you are using .NET Core 2.x (in beta as of July/2017), check Joe's answer.

Original answer:

Recommended read: Porting to .NET Core

I quote:

  • System.Data. While the base layer is already part of .NET Core, i.e. the provider model and SQL client, some features are currently not available, such as schema support and DataTable/DataSet.

You can use SqlDataReader but not SqlAdapter or DataTable.

Start by adding System.Data.SqlClient NuGet Package.

Then you can...

var con = new SqlConnection("...");
var cmd = con.CreateCommand();
cmd.CommandText = "...";
var reader = cmd.ExecuteReader();
// populate your custom data structure

Does IList<Dictionary<string, object>> works for you?

var results = new List<Dictionary<string, object>>();

while (reader.Read())
{
    results.Add(Enumerable.Range(0, reader.FieldCount).ToDictionary(reader.GetName, reader.GetValue));
}
return results;

So now you can read using results[0]["FirstName"].ToString()

Unless you want to switch to Entity Framework Core, in that case this tutorial is handy.

Gerardo Grignoli
  • 14,058
  • 7
  • 57
  • 68
6

Instead of DataAdapter/DataTable you may use one of the existing DAL libraries for .NET Core that support CRUD operations over low-level ADO.NET interfaces. Recently I've published NReco.Data: provider-independent DAL that supports automatic SQL statements generation, abstract queries and simple record CRUD operations.

For example, code snippet from the question can be reimplemented in the following way:

var con = new SqlConnection(m_ConnectString);
var dbFactory = new NReco.Data.DbFactory(
    System.Data.SqlClient.SqlClientFactory.Instance);
var dbCmdBuilder = new NReco.Data.DbCommandBuilder(dbFactory);
var dbAdapter = new NReco.Data.DbDataAdapter(con, dbCmdBuilder);

var selectRecordsList = dbAdapter.Select( 
    new Query("some_table") ).ToList<Dictionary<string,object>>();

Complex SQL queries may be executed as application-level data views:

dbCmdBuilder.Views["some_view"] = new DbDataView(
    @"SELECT @columns FROM Employee emp
      LEFT JOIN Company c ON (c.Id=emp.CompanyId)
      @where[ WHERE {0}] @orderby[ ORDER BY {0}]
    ") {
      FieldMapping = new Dictionary<string,string>() {
        {"Id", "emp.Id"},
        {"*", "emp.*, c.Title as CompanyTitle"}
      }
    };
var someViewRS = dbAdapter.Select( new Query("some_view") ).ToRecordSet();

NReco.Data doesn't try to replace SQL with the its own Query (like LINQ does); instead of that it allows you to make simple DB-independent queries from business logic and encapsulate complex SQL syntax with special app-level dataviews that accessed like read-only tables.

Also it is possible to specify raw SQL query directly with Select method overload (like FromSql in EF Core):

var userModels = dbAdapter.Select("select * from users where id={0}", 5).ToList<User>();
Vitaliy Fedorchenko
  • 8,447
  • 3
  • 37
  • 34
  • Thanks for all the responses. I have used DataReader and a lightweight data table (which is basically a Lists of Lists) – Hughgo Jul 28 '16 at 09:42
  • @Hughgo using DataReader is a simplest (and best-performance) solution of course :) I hope you'll try NReco.Data library on occasion. Don't hesitate to contact me in case of any questions or issues. – Vitaliy Fedorchenko Jul 28 '16 at 09:58
  • How on earth did you get such a project off the ground when your query objects are restricted to a named table? What about the literally millions of cases outside the playpen where a data source query might be dynamic sql, or a join, etc? – ProfK Jul 01 '17 at 05:01
  • 1
    @ProfK Query is a generic structure that holds conditions and other options; it doesn't restricted to tables - you can specify database dataview or encapsulate complex SQL query (with JOINs, GROUP BY etc) as app-level dataview (see DbDataView class, it can be registered in DbCommandBuilder.Views). After all, you can provide raw SQL query like in EF Core or Dapper. – Vitaliy Fedorchenko Jul 04 '17 at 08:28
  • Thanks, @VitaliyFedorchenko, I wasn't away of that. An answer with a little example how to use raw SQL vs. a named DB artefact in a `Query` object will get you the bounty. I can't just make a named view for each query I may want to run. – ProfK Jul 05 '17 at 06:07
  • @ProfK I've added code snippets that illustrate how to use app-level dataviews for complex SQL queries and raw SQL. – Vitaliy Fedorchenko Jul 05 '17 at 12:35
  • Thanks, @VitaliyFedorchenko. A few hours before I can give you the bounty, but otherwise it's yours. – ProfK Jul 05 '17 at 13:01
3

You can use DbDataAdapter link for more info

Then use this function for CreateDataAdapter

private static DbDataAdapter CreateDataAdapter(this DbConnection connection, DbCommand command)
{
     var adp = DbProviderFactories.GetFactory(connection).CreateDataAdapter();
     adp.SelectCommand = command;
     return adp;
 }

Then normal can use like code below

var connection = Context.Database.GetDbConnection();
using var command = connection.CreateCommand();
command.CommandText = cmdText;
using DbDataAdapter adp = connection.CreateDataAdapter(command);

After you can fill

using DataSet dataSet = new DataSet();
adp.Fill(dataSet);
Zanyar Jalal
  • 1,407
  • 12
  • 29
  • 1
    This is the best and fastest way provided directly in .NET API rather than using any third party nuget libraries or wout developing any extension methods. Even simpler code : `using (SqlConnection dbCD = new SqlConnection()) { dbCD.Open(); using (SqlCommand cmd = dbCD.CreateCommand()) { cmd.CommandText = "SELECT * FROM tableName"; var adp = DbProviderFactories.GetFactory(dbCD).CreateDataAdapter(); adp.SelectCommand = cmd; adp.Fill(MyDataSets); } dbCD.Close(); }` – sanpat Aug 28 '20 at 20:45