Best method for Populating DataSet from a SQLDataReader - sql

I am working on a DAL that is getting a DataReader Asynchronously.
I would like to write a single method for transforming the DataReader into a DataSet. It needs to handle different schema so that this one method will handle all of my fetch needs.
P.S. I am populating the SQLDataReader Asynchronously, please don't give answers that are getting rid of the DataReader.

DataTable.load() can be used for a generic approach.
do {
var table = new DataTable();
table.Load(reader);
dataset.Tables.Add(table);
} while(!reader.IsClosed);

Try DataSet.Load(). It has several overloads taking an IDataReader.

If for some reason the Load method fails, here is a manual way to do it:
DataTable dt = new DataTable();
dt = sdr.GetSchemaTable();
//dt.Constraints.Clear();
//dt.PrimaryKey = null;
//dt.BeginLoadData();
if (sdr.HasRows)
{
DataRow row;
while (sdr.Read())
{
row = dt.NewRow();
sdr.GetValues(row.ItemArray);
dt.Rows.Add(row);
}
Another way is to use SqlTableAdapter:
var adapter = new SqlDataAdapter(command);
DataSet ds = new DataSet();
adapter.Fill(ds);

Related

In a `SqlCommand`, what timespan does the `CommandTimeout` actually represent?

I am querying a Microsoft SQL Database using the SqlConnection, SqlCommand and SqlReader, much like described in https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/retrieving-data-using-a-datareader
Now, an SqlCommand allows to set the CommandTimeout, and I am doing it like so (simplified):
using (SqlConnection connection = GetConnection()) {
connection.Open();
using (SqlCommand command = connection.CreateCommand()) {
command.CommandText = query; //My custom SQL query
command.CommandType = CommandType.Text;
//Set Timeout
command.CommandTimeout = timeout.Value; //My custom timeout
using (SqlDataReader reader = command.ExecuteReader()) {
while (reader.Read()) {
//Read row by row and do stuff
}
}
}
}
My question is, to what does the Timeout actually apply to? Is it
The time spent in ExecuteReader()
The time spent in Read()
both of those
something else?
There seems no documentation of this specifically, neither in MSDN nor on the web.
It will apply to the time executing the command against the database which is command.ExecuteReader() which is complete by the time you start reading the records. You could test that by putting a break point in after that on the while and and sitting there - you won't hit your timeout.

Getting SQL error while reading the data

SqlCommand cmd = new SqlCommand("SELECT * FROM Products",con);
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
if (reader["ProductName"].ToString() == "dsd")
{
SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM Products", con);
DataSet ds = new DataSet();
da.Fill(ds);
ListView1.DataSource = ds;
ListView1.DataBind();
}
}
reader.Close();
Error :
Already an open DataReader associated with this Command which must be closed first
I am getting error on this line da.fill(ds). And I used two commands one SqlCommand to read the record and second SqlDataAdapter to show record.
If I understand your problem correctly, you need to bind a listview control with all the products by name "dsd".
If this is correct, you can change the SQL query like this:
SELECT * FROM Products WHERE ProductName = 'dsd'
You can read the response from the DataReader and prepare the List to bind to your listview control. I don't think you need DataSet to bind to listview control.
You need two connection objects. One for your open data reader and a second to use with the SqlDataAdapter.
(Or you can use MARS, but really it is far better to just open a second connection.)

Petapoco: How to databind gridview using join from two tables?

I dont want to do using a custom class.
var q = db.Query<dynamic>(query); //This does not work
query has joins and custom created columns from multiple tables.
You can check the PetaPoco.cs "ExecuteReader" method to see if it looks something like this(see code below):
my file did not have any code in the function so I model it after Execute scalar method.
this will return a generic DataTable that is perfectly bindable to datagrid.
however keep in mind that to make any changes to the data you will need to implement
your own CRUD methods as the resulting DataTable is readonly.
//Execute Reader
public DataTable ExecuteReader(string sql, params object[] args)
{
try
{
OpenSharedConnection();
try
{
using (var cmd = CreateCommand(_sharedConnection, sql, args))
{
var val = cmd.ExecuteReader();
OnExecutedCommand(cmd);
var dt = new DataTable();
dt.Load(val);
return dt; //(T)Convert.ChangeType(val, typeof(T));
}
}
finally
{
CloseSharedConnection();
}
}
catch (Exception x)
{
OnException(x);
throw;
}
}
public DataTable ExecuteReader(Sql sql)
{
return ExecuteReader(sql.SQL, sql.Arguments);
}
Create a class that contains the fields from the two tables you want to display in the grid.
Populate your query with a SQL statement that joins the tables and returns the columns you need.
Then
var q=db.Query<YourClassName>.Query(query)
should work.
You can create a database view, and then the T4 templates will automatically generate the class for that. You need to add
IncludeViews = true;
to Database.tt

Why calling DataTable.Clear() then DBDataAdapter.Update(DataTable) does not clear the table in database?

I try to use the code sample in DBDataAdapter.Update Method to clear a table in a database.
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlDataAdapter adapter = new SqlDataAdapter("SELECT * FROM WebCam", connection);
DataTable table = new DataTable();
adapter.Fill(table);
table.PrimaryKey = new DataColumn[] { table.Columns["Date"] };
//table.Rows[0]["Date"] = System.DateTime.Now; //It's OK to modify a row
table.Clear(); //But it is not working to clear the table
SqlCommandBuilder builder = new SqlCommandBuilder(adapter);
adapter.Update(table);
}
I can add new rows or modify existing rows, and the changes can be committed to the database, but if I try to empty the table, the change to 'table' can not be committed to the database, also, no exception is thrown.
Do I miss something?
u should get error on this line:
table.PrimaryKey = new DataColumn[] { table.Columns["Date"] };
this would mean that u have catched the exception somewhere else, maybe from where the function is being called, and not showing the error in a messege box.
Another reason might be because you are using words like Table, adapter etc ... my guess is that you might be overloading some reserved words functionalities.

Reading and Updating Data Using SqlDataAdapter Question

I'm looking for some examples on how to best use SqlDataAdapter to access and update data in my application.
Right now I have something like this:
SqlDataAdapter adapter;
DataSet myData = MyDataAccessClass.GetData("Select * from Students", ref adapter);
// change some data here and save changes
adapter.Update();
All of this occurs in code behind, and I dont really like it at all.
So, I'm trying to find a way to do something like this:
DataSet myData = MyDataAccessClass.GetStudents();
// change some data and save changes
MyDataAccessClass.SaveStudents(myData);
Where SaveStudents method still uses SqlDataAdapter to update db.
Any ideas on how to make this work or some pointers to best practices of doing
something like this are highly appreciated. Thank you.
That seems like a fairly basic Data Access Layer implementation, to me. Generally, I do it something like this:
public class MyDataAccessClass
{
private string ConnString;
public MyDataAccessClass()
{ //Get connection string from configuration file }
public MyDataAccessClass(string connString)
{ ConnString = connString; }
public DataSet GetAllStudents()
{
//your SQL Adapter code here...
}
}
One note that I'd make is that with so many ORM solutions (including just Entity Framework and Linq2Sql) available, you may want to consider using collections of objects instead of data-sets for your Data Representations. Then you can have a method like:
public void CreateUpdateStudent(Student student)
{
//update database
}
That's fairly subjective, I'll admit, but I find it preferable to using straight DataSets.
If you want to get update data using the sql-data-adapter then you could use these
Using System.Data.SqlClient;
SqlConnection con = new SqlConnection("Data Source=abcd-pc;Initial Catalog=user_info;Integrated Security=True");
SqlDataAdapter da = new SqlDataAdapter();
try
{
da.UpdateCommand = new SqlCommand("Update logindemo set password=#pswd where username=#uname",con);
da.UpdateCommand.Parameters.Add("#pswd", SqlDbType.VarChar).Value = txtpass.Text;
da.UpdateCommand.Parameters.Add("#uname", SqlDbType.VarChar).Value = txtusername.Text;
con.Open();
da.UpdateCommand.ExecuteNonQuery();
Label1.Text = "Data Updated";
con.Close();
}
catch
{
Label1.Text = "Unable To Connect";
}
I hope you understand how to update the data easily. It just like the example. You can use these type of example in Inserting into the Data, and Deleting the Data with using specific the command and sql query as it required.