I am working on a huge set of data, and using CLR for processing it. The CLR processing is working quick, but I need a quick way to move the processed data to the database(through CLR).
For example, see the following clr code
protected static string Normalize(string s) // space and special character remover
{
char[] arr = s.ToCharArray();
arr = Array.FindAll<char>(arr, (c => char.IsLetterOrDigit(c)));
return new string(arr).ToLower();
}
[Microsoft.SqlServer.Server.SqlProcedure]
public static void udpNormStr ()
{
SqlConnection con = new SqlConnection("context connection = true");
SqlCommand cmd = new SqlCommand("Select cName from NamesTable", con);
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
DataTable fill = new DataTable();
fill.Columns.Add("NormName", typeof(string));
da.Fill(dt);
cmd.CommandText = "insert into NormTable values (#nName)";
cmd.Parameters.Add("#nName", SqlDbType.VarChar);
foreach (DataRow row in dt.Rows)
{
fill.Rows.Add(Normalize(row[0].ToString()));
}
con.Open();
foreach (DataRow row in fill.Rows)
{
cmd.Parameters["#nName"].Value = row[0];
cmd.ExecuteNonQuery();
}
con.Close();
}
It is taking lot of time to execute, and is wasting 90% of that time in the insert operations.
Please suggest a better way of moving processed data to database(through CLR).
SqlBulkCopy; since you have a DataTable already, you can use:
using (var bcp = new SqlBulkCopy(con))
{
bcp.DestinationTableName = "NormTable";
bcp.WriteToServer(dt);
}
Note that for streaming data, you can also create a custom IDataReader implementation and feed that to WriteToServer.
Wrap your connection with a SqlTransaction to avoid implicit transactions.
con = new SqlConnection("context connection=true");
con.Open();
using (con)
{
using (var sqlTrans = con.BeginTransaction()) //one transaction instead of many from each insert implicit
{
const string cmdText = #"INSERT INTO [table1] ([a],[b],[c],[d],[e]) VALUES (#a,#b,#c,#d,#e)";
using (var cmd = new SqlCommand(cmdText, con, sqlTrans))
{
var aField = cmd.Parameters.Add("#a", SqlDbType.NVarChar, 255);
var bField = cmd.Parameters.Add("#b", SqlDbType.Int);
var cField = cmd.Parameters.Add("#c", SqlDbType.Bit);
var dField = cmd.Parameters.Add("#d", SqlDbType.NVarChar, 255);
var eField = cmd.Parameters.Add("#e", SqlDbType.Int);
//same for all
cField.Value = false;
dField.Value = "d";
eField.Value = 1;
foreach (var someValue in valueCollection)
{
aField.Value = someValue.Key;
bField.Value = someValue.Value;
cmd.ExecuteNonQuery();
}
}
sqlTrans.Commit();
}
con.Close();
}
If this work is SQL/CLR, then that is tricky. One idea might be to make that method only return the data, for example as a CLR Table-Valued Function, and then do the INSERT back in TSQL pulling from the table-valued function.
Try to use SQLBulkCopy Class
this is sample method to Inset DataTable to Database in one Shot
public static bool SaveDetails(DataTable dbTable)
{
try
{
SqlConnection conn = new SqlConnection("Data Source=akshay;Initial Catalog=CosmosDB;User Id=sa;Password=Nttdata123");
conn.Open();
SqlBulkCopy sbc = new SqlBulkCopy(conn);
if (dbTable.Rows.Count > 0)
{
sbc.DestinationTableName = "Employee";
sbc.WriteToServer(dbTable);
}
sbc.Close();
conn.Close();
return true;
}
catch (Exception exp)
{
return false;
}
}
Related
I am getting the above mentioned exception for the following code:-
public bool insert(tdata data)
{
SqlTransaction sqlTransaction = null;
try
{
int partid = 0, strid = 0;
var status = 1;
var load = Convert.ToInt32(data.load);
var vload = Convert.ToInt32(data.iVerticalLoad);
sqlConn.Open();
sqlTransaction = sqlConn.BeginTransaction();
//Insert Part into table 1
string sqlquery = "";
SqlCommand cmd = new SqlCommand(sqlquery, sqlConn, sqlTransaction);
cmd.ExecuteNonQuery();
//Get Part IDs
string sqlquery1 = "";
SqlDataAdapter da1 = new SqlDataAdapter(sqlquery1, sqlConn);
DataTable dt1 = new DataTable();
da1.Fill(dt1);
foreach (DataRow row in dt1.Rows)
{
partid = Convert.ToInt32(row["PartID"]);
}
//Get STR ID
string sqlquery2 = "";
SqlDataAdapter da2 = new SqlDataAdapter(sqlquery2, sqlConn);
DataTable dt2 = new DataTable();
da2.Fill(dt2);
foreach (DataRow row in dt2.Rows)
{
strid = Convert.ToInt32(row["STRID"]);
}
//Check whether Type is NULL.
if(data.type != null)
{
//Insert in table 2
string sqlquery4 = "";
SqlCommand cmd4 = new SqlCommand(sqlquery4, sqlConn, sqlTransaction);
cmd4.ExecuteNonQuery();
}
else
{
sqlTransaction?.Rollback();
return false;
}
sqlTransaction.Commit();
sqlConn.Close();
return true;
}
catch (Exception eI)
{
sqlTransaction?.Rollback();
throw eI;
}
}
Since, I need to make sure that part is inserted in both table 1 and table 2 or not stored in either, I have kept the transaction commit at last. I have also put sql transaction part of sqlcmd before ExecuteNonQuery. Yet I am getting the exception at Get Part IDs section. What have I missed?
SqlDataAdapter uses a SqlCommand under the hood, which also needs to be attached to the transaction. You can hook it up using adapter.SelectCommand.Transaction = yourTransaction;
But in this case, you only want a single row seemingly, so just use SqlCommand.ExecuteScalar
Note also:
Always put SqlConnection SqlCommand SqlDataAdapter and SqlTransaction in using. This ensures they are disposed properly. In the case of a transaction, this also rolls back automatically if you have not committed.
Do not cache the connection object. Create and dispoe as mentioned.
Always parameterize your SQL statements. Do not inject data into your queries.
I strongly suspect this could all have been done in a single batch. But as you haven't show your SQL I can't say.
bail out on the null check at the beginning, to save having to open the connection.
public bool insert(tdata data)
{
//Check whether Type is NULL.
if(data.type != null)
return false;
int partid = 0, strid = 0;
var status = 1;
var load = Convert.ToInt32(data.load);
var vload = Convert.ToInt32(data.iVerticalLoad);
using var sqlConn = new SqlConnection(YourConnString);
sqlConn.Open();
using var sqlTransaction = sqlConn.BeginTransaction();
//Insert Part into table 1
const string sqlquery = "";
using (SqlCommand cmd = new SqlCommand(sqlquery, sqlConn, sqlTransaction))
{
// add parameters here
// cmd.Parameters.Add("#someParam", SqlDbType.Whatever, 100).Value = paramValue;
cmd.ExecuteNonQuery();
}
//Get Part IDs
const string sqlquery1 = "";
using (SqlCommand cmd = new SqlCommand(sqlquery1, sqlConn, sqlTransaction))
{
// add parameters here
// cmd.Parameters.Add("#someParam", SqlDbType.Whatever, 100).Value = paramValue;
partid = (int)cmd.ExecuteScalar();
}
//Get STR ID
const string sqlquery2 = "";
using (SqlCommand cmd = new SqlCommand(sqlquery2, sqlConn, sqlTransaction))
{
// add parameters here
// cmd.Parameters.Add("#someParam", SqlDbType.Whatever, 100).Value = paramValue;
strid = (int)cmd.ExecuteScalar();
}
//Insert in table 2
const string sqlquery4 = "";
using (SqlCommand cmd = new SqlCommand(sqlquery4, sqlConn, sqlTransaction))
{
// add parameters here
// cmd.Parameters.Add("#someParam", SqlDbType.Whatever, 100).Value = paramValue;
cmd4.ExecuteNonQuery();
}
sqlTransaction.Commit();
return true;
}
This is probably a simple question but I am not experienced in C#.
I have 2 datatables, 1 is basically a copy of the other (like a table to review information). To set the values this is what I am doing now:
string attribute1 = "";
string attribute2 = "";
string attribute3 = "";
.....
DataTable result = new DataTable();
using (SqlConnection con = new SqlConnection("user id=user_id;password=pwd;server=serverstring;Trusted_Connection=yes;database=database;connection timeout=30"))
{
using (SqlCommand cmd = new SqlCommand("SELECT * FROM table1 WHERE parameter=#identifying_parameter", con))
{
cmd.Parameters.AddWithValue("#identifying_parameter", "example");
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
if (reader.Read())
{
attribute1 = Convert.ToString(reader["attribute1"]);
attribute2 = Convert.ToString(reader["attribute2"]);
attribute3 = Convert.ToString(reader["attribute3"]);
.....
}
con.Close();
}
}
using (SqlConnection con = new SqlConnection("user id=user_2;password=pwd;server=serverstring;Trusted_Connection=yes;database=database;connection timeout=30"))
{
using (SqlCommand cmd = new SqlCommand("INSERT INTO table2 (attribute1, attribute2, attribute3, ...) VALUES(#attribute1, #attribute2, #attribute3, ...)", con))
{
cmd.Parameters.AddWithValue("#attribute1", attribute1);
cmd.Parameters.AddWithValue("#attribute2", attribute2);
cmd.Parameters.AddWithValue("#attribute3", attribute3);
....
con.Open();
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(result);
con.Close();
da.Dispose();
}
}
Obviously I might have a lot of attributes, so is there a simpler way to set every attribute in the table to be equal in C#?
You can use INSERT..INTO..SELECT
DataTable result = new DataTable();
using (SqlConnection con = new SqlConnection("user id=user_2;password=pwd;server=serverstring;Trusted_Connection=yes;database=database;connection timeout=30"))
{
using (SqlCommand cmd = new SqlCommand(#"INSERT INTO table2 (attribute1, attribute2, attribute3, ...)
SELECT attribute1, attribute2, attribute3 ... FROM table1
WHERE parameter=#identifying_parameter
", con))
{
cmd.Parameters.AddWithValue("#identifying_parameter", "example");
con.Open();
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(result);
con.Close();
da.Dispose();
}
}
You can use * instead of specifying the column name, although which is not good practice..
In order to make a second Table identical (or "equivalent" as per your definition) to the first one (for certainty let's call it sourceTable), you can use SqlBulkCopy.WriteToServer Method (DataTable)(re: https://msdn.microsoft.com/en-us/library/ex21zs8x%28v=vs.110%29.aspx)
using (SqlConnection YourConnection= new SqlConnection(YourConnectionString))
{
YourConnection.Open();
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(YourConnection))
{
bulkCopy.DestinationTableName = "dbo.YourDestinationTable";
try
{
// Write from the source to the destination.
bulkCopy.WriteToServer(sourceTable);
}
catch (Exception ex) { }
}
}
In order to get a sourceTable you can use the following code snippet:
DataTable sourceTable = SqlReadDB(YourConnString, "SELECT *")
private static DataTable SqlReadDB(string ConnString, string SQL)
{
DataTable _dt;
try
{
using (SqlConnection _connSql = new SqlConnection(ConnString))
{
using (SqlCommand _commandl = new SqlCommand(SQL, _connSql))
{
_commandSql.CommandType = CommandType.Text;
_connSql.Open();
using (SqlCeDataReader _dataReaderSql = _commandSql.ExecuteReader(CommandBehavior.CloseConnection))
{
_dt = new DataTable();
_dt.Load(_dataReaderSqlCe);
_dataReaderSql.Close();
}
}
_connSqlCe.Close();
return _dt;
}
}
catch { return null; }
}
}
Hope this may help.
I'm writing a stored procedure that currently contains only a SELECT query. It will be expanded to do a number of other things, which is why it has to be a stored procedure, but for now, it is a simple query.
Something like this:
SELECT name, occupation, position
FROM jobs
WHERE ...
I'm looking to return the results of this query to be used in C#. I want to add it to a list so that I can bind it to a GridView component.
I don't know how to go about this, though. If I have to insert it into a list after returning all selected data, then that's alright, I just need to know how to properly return the data so that I can do that.
If I can return it in a format that can be popped right into a list, though, that would be ideal.
In stored procedure, you just need to write the select query like the below:
CREATE PROCEDURE TestProcedure
AS
BEGIN
SELECT ID, Name
FROM Test
END
On C# side, you can access using Reader, datatable, adapter.
Using adapter has just explained by Susanna Floora.
Using Reader:
SqlConnection connection = new SqlConnection(ConnectionString);
command = new SqlCommand("TestProcedure", connection);
command.CommandType = System.Data.CommandType.StoredProcedure;
connection.Open();
SqlDataReader reader = command.ExecuteReader();
List<Test> TestList = new List<Test>();
Test test = null;
while (reader.Read())
{
test = new Test();
test.ID = int.Parse(reader["ID"].ToString());
test.Name = reader["Name"].ToString();
TestList.Add(test);
}
gvGrid.DataSource = TestList;
gvGrid.DataBind();
Using dataTable:
SqlConnection connection = new SqlConnection(ConnectionString);
command = new SqlCommand("TestProcedure", connection);
command.CommandType = System.Data.CommandType.StoredProcedure;
connection.Open();
DataTable dt = new DataTable();
dt.Load(command.ExecuteReader());
gvGrid.DataSource = dt;
gvGrid.DataBind();
I hope it will help you. :)
SqlConnection connection = new SqlConnection(ConnectionString);
command = new SqlCommand("TestProcedure", connection);
command.CommandType = System.Data.CommandType.StoredProcedure;
connection.Open();
DataTable dt = new DataTable();
dt.Load(command.ExecuteReader());
gvGrid.DataSource = dt;
gvGrid.DataBind();
SqlConnection con = new SqlConnection("Data Source=DShp;Initial Catalog=abc;Integrated Security=True");
SqlDataAdapter da = new SqlDataAdapter("data", con);
da.SelectCommand.CommandType= CommandType.StoredProcedure;
DataSet ds=new DataSet();
da.Fill(ds, "data");
GridView1.DataSource = ds.Tables["data"];
GridView1.DataBind();
Passing Parameters in Stored Procedure and calling it in C# Code behind as shown below?
SqlConnection conn = new SqlConnection(func.internalConnection);
var cmd = new SqlCommand("usp_CustomerPortalOrderDetails", conn);
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.Add("#CustomerId", SqlDbType.Int).Value = customerId;
cmd.Parameters.Add("#Qid", SqlDbType.VarChar).Value = qid;
conn.Open();
// Populate Production Panels
DataTable listCustomerJobDetails = new DataTable();
listCustomerJobDetails.Load(cmd.ExecuteReader());
conn.Close();
I had the same question, took me ages to find a simple solution.
Using ASP.NET MVC 5 and EF 6:
When you add a stored procedure to your .edmx model, the result of the stored procedure will be delivered via an auto-generated object called yourStoredProcName_result.
This _result object contains the attributes corresponding to the columns in the database that your stored procedure selected.
The _result class can be simply converted to a list:
yourStoredProcName_result.ToList()
// GET: api/GetStudent
public Response Get() {
return StoredProcedure.GetStudent();
}
public static Response GetStudent() {
using (var db = new dal()) {
var student = db.Database.SqlQuery<GetStudentVm>("GetStudent").ToList();
return new Response {
Sucess = true,
Message = student.Count() + " Student found",
Data = student
};
}
}
Building on some of the responds here, i'd like to add an alternative way. Creating a generic method using reflection, that can map any Stored Procedure response to a List. That is, a List of any type you wish, as long as the given type contains similarly named members to the Stored Procedure columns in the response.
Ideally, i'd probably use Dapper for this - but here goes:
private static SqlConnection getConnectionString() // Should be gotten from config in secure storage.
{
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
builder.DataSource = "it.hurts.when.IP";
builder.UserID = "someDBUser";
builder.Password = "someDBPassword";
builder.InitialCatalog = "someDB";
return new SqlConnection(builder.ConnectionString);
}
public static List<T> ExecuteSP<T>(string SPName, List<SqlParameter> Params)
{
try
{
DataTable dataTable = new DataTable();
using (SqlConnection Connection = getConnectionString())
{
// Open connection
Connection.Open();
// Create command from params / SP
SqlCommand cmd = new SqlCommand(SPName, Connection);
// Add parameters
cmd.Parameters.AddRange(Params.ToArray());
cmd.CommandType = CommandType.StoredProcedure;
// Make datatable for conversion
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(dataTable);
da.Dispose();
// Close connection
Connection.Close();
}
// Convert to list of T
var retVal = ConvertToList<T>(dataTable);
return retVal;
}
catch (SqlException e)
{
Console.WriteLine("ConvertToList Exception: " + e.ToString());
return new List<T>();
}
}
/// <summary>
/// Converts datatable to List<someType> if possible.
/// </summary>
public static List<T> ConvertToList<T>(DataTable dt)
{
try // Necesarry unfotunately.
{
var columnNames = dt.Columns.Cast<DataColumn>()
.Select(c => c.ColumnName)
.ToList();
var properties = typeof(T).GetProperties();
return dt.AsEnumerable().Select(row =>
{
var objT = Activator.CreateInstance<T>();
foreach (var pro in properties)
{
if (columnNames.Contains(pro.Name))
{
if (row[pro.Name].GetType() == typeof(System.DBNull)) pro.SetValue(objT, null, null);
else pro.SetValue(objT, row[pro.Name], null);
}
}
return objT;
}).ToList();
}
catch (Exception e)
{
Console.WriteLine("Failed to write data to list. Often this occurs due to type errors (DBNull, nullables), changes in SP's used or wrongly formatted SP output.");
Console.WriteLine("ConvertToList Exception: " + e.ToString());
return new List<T>();
}
}
Gist: https://gist.github.com/Big-al/4c1ff3ed87b88570f8f6b62ee2216f9f
May be this will help:
Getting rows from DB:
public static DataRowCollection getAllUsers(string tableName)
{
DataSet set = new DataSet();
SqlCommand comm = new SqlCommand();
comm.Connection = DAL.DAL.conn;
comm.CommandType = CommandType.StoredProcedure;
comm.CommandText = "getAllUsers";
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = comm;
da.Fill(set,tableName);
DataRowCollection usersCollection = set.Tables[tableName].Rows;
return usersCollection;
}
Populating DataGridView from DataRowCollection :
public static void ShowAllUsers(DataGridView grdView,string table, params string[] fields)
{
DataRowCollection userSet = getAllUsers(table);
foreach (DataRow user in userSet)
{
grdView.Rows.Add(user[fields[0]],
user[fields[1]],
user[fields[2]],
user[fields[3]]);
}
}
Implementation :
BLL.BLL.ShowAllUsers(grdUsers,"eusers","eid","euname","eupassword","eposition");
I have SQL Server CE 3.5 database. I run the following code:
private void Load(string sql)
{
if (connection.State != ConnectionState.Open)
connection.Open();
SqlCeDataAdapter sqlCeDataAdapter = new SqlCeDataAdapter(sql, connection);
Stopwatch watch = new Stopwatch();
DataSet dataSet = new DataSet();
try
{
Cursor.Current = Cursors.WaitCursor;
watch.Start();
sqlCeDataAdapter.Fill(dataSet, "items");
sqlCeDataAdapter.Dispose();
var myBind = new BindingSource(dataSet, "items");
grid.DataSource = myBind;
}
finally
{
watch.Stop();
Cursor.Current = Cursors.Default;
MessageBox.Show(watch.ElapsedMilliseconds.ToString());
}
}
Load ("select a1, a2 from table");
Is it long for SQL Server CE, or should it be faster loaded?
What can I do to make this select faster?
When I use joins with other table, the time dramatically grows up ...
EDIT:
I have change the code for a following new version, but still 7.5 s. ...
private void Load2 (string sql)
{
if (connection.State != System.Data.ConnectionState.Open)
{
connection.Open();
}
using (SqlCeCommand command = new SqlCeCommand(sql, connection))
{
Stopwatch watch = new Stopwatch();
Cursor.Current = Cursors.WaitCursor;
watch.Start();
using (SqlCeDataReader reader = command.ExecuteReader())
{
DataSet dataSet = new DataSet();
dataSet.Tables.Add("items");
dataSet.Tables["items"].Columns.Add("s1");
dataSet.Tables["items"].Columns.Add("s2");
while (reader.Read())
{
string s1 = reader.GetString(0);
string s2 = reader.GetString(1);
dataSet.Tables["items"].Rows.Add(s1, s2);
}
watch.Stop();
Cursor.Current = Cursors.Default;
MessageBox.Show(watch.ElapsedMilliseconds.ToString());
BindingSource binding = new BindingSource(dataSet, "items");
grid.DataSource = binding;
}
}
}
SqlCeDataAdapter.Fill(...) is just notoriously slow. If you really need the performance you will need to use a SqlCeDataReader instead.
private void Load(string sql) {
if (connection.State != System.Data.ConnectionState.Open) {
connection.Open();
}
using (SqlCeCommand command = new SqlCeCommand(sql, connection)) {
using (SqlCeDataReader reader = command.ExecuteReader()) {
DataSet dataSet = new DataSet();
dataSet.Tables.Add("items");
while (reader.Read()) {
DataRow row = dataSet.Tables["items"].NewRow();
// fill your row
dataSet.Tables["items"].Rows.Add(row);
}
BindingSource binding = new BindingSource(dataSet, "items");
grid.DataSource = binding;
}
}
}
And of course add your proper error handling, and clean it up to your liking. There's also Entity Framework which is decent on performance compared to a DbDataAdapter implementation.
Because you are using SqlCe, you have other limiting factors like disk IO, and you don't have a server processing SQL transactions with any sort of optimizations.
The question is old, but I wanna give a quick solution for googlers who may find it today :
I can query 129000 values in ~800ms with it.
var query = "SELECT timestamp FROM " + tablename;
SqlCeCommand cmdGetOldMasterId = new SqlCeCommand(query, _con);
SqlCeDataReader reader = cmdGetOldMasterId.ExecuteReader();
var queried_data = new List<int>();
while(reader.Read())
{
queried_data.Add(reader.GetInt32(0));
}
Of course you have to adapt the code to your needs, so f.e. if you wanna grab string you need to change the reader.Get command, the list ect.
I've read a lot of posts about inserting a DataTable into a SQL table, but is there an easy way to pull a SQL table into a .NET DataTable?
Here, give this a shot (this is just a 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();
}
}
var table = new DataTable();
using (var da = new SqlDataAdapter("SELECT * FROM mytable", "connection string"))
{
da.Fill(table);
}
Lots of ways.
Use ADO.Net and use fill on the data adapter to get a 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);
}
You can then get the data table out of the dataset.
Note in the upvoted answer dataset isn't used, (It appeared after my answer)
It does
// create data adapter
SqlDataAdapter da = new SqlDataAdapter(cmd);
// this will query your database and return the result to your datatable
da.Fill(dataTable);
Which is preferable to mine.
I would strongly recommend looking at entity framework though ... using datatables and datasets isn't a great idea. There is no type safety on them which means debugging can only be done at run time. With strongly typed collections (that you can get from using LINQ2SQL or entity framework) your life will be a lot easier.
Edit: Perhaps I wasn't clear: Datatables = good, datasets = evil. If you are using ADO.Net then you can use both of these technologies (EF, linq2sql, dapper, nhibernate, orm of the month) as they generally sit on top of ado.net. The advantage you get is that you can update your model far easier as your schema changes provided you have the right level of abstraction by levering code generation.
The ado.net adapter uses providers that expose the type info of the database, for instance by default it uses a sql server provider, you can also plug in - for instance - devart postgress provider and still get access to the type info which will then allow you to as above use your orm of choice (almost painlessly - there are a few quirks) - i believe Microsoft also provide an oracle provider. The ENTIRE purpose of this is to abstract away from the database implementation where possible.
Vendor independent version, solely relies on ADO.NET interfaces; 2 ways:
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];
}
}
}
}
I did some performance testing, and the second approach always outperformed the first.
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());
Read1 looks better on eyes, but data adapter performs better (not to confuse that one db outperformed the other, the queries were all different). The difference between the two depended on query though. The reason could be that Load requires various constraints to be checked row by row from the documentation when adding rows (its a method on DataTable) while Fill is on DataAdapters which were designed just for that - fast creation of DataTables.
Centerlized Model: You can use it from any where!
You just need to call Below Format From your function to this class
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);
That's it. it's perfect method.
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;
}
}