How to convert collections to DataTable for Ado.Net SqlDataAdapter.Update? - c#

How to finish the following function which accept three collection parameters for deleted, inserted and updated records and convert the collections to a DataTable for DataAdapter to update the table?
I found a way to convert List to DataTable at How to fill a datatable with List<T>. However, it doesn't set the insert, update and delete flags in DataTable?
void Save(
IEnumerable<int> deleted,
IEnumerable<Poco1> inserted,
IEnumerable<Poco1> updated)
{
var dt = new DataTable();
.... // Initialize dt with deleted, inserted and update?
using (var con = new SqlConnection(ConnectionStr))
{
con.Open();
var da = new SqlDataAdapter("select * from table", con);
da.Update(dt);
}
}
Or is there a better way to update the database table from these three collections? (C# 3.5)

First off, your going to want to also define the Insert, Update and Delete commands:
// Create the other commands.
da.InsertCommand = new SqlCommand("...how to insert");
da.UpdateCommand = new SqlCommand("...how to update");
da.DeleteCommand = new SqlCommand("...how to delete");
Alternatively you can try to use DbCommandBuilder to do it for you at runtime:
// Create the DbCommandBuilder.
DbCommandBuilder builder = factory.CreateCommandBuilder();
builder.DataAdapter = da;
// Get the insert, update and delete commands.
da.InsertCommand = builder.GetInsertCommand();
da.UpdateCommand = builder.GetUpdateCommand();
da.DeleteCommand = builder.GetDeleteCommand();
Next you need to define the DataTables to match the table you are targeting:
DataTable dt = new DataTable();
dt.Columns.Add(add your columns...)
Then you need to add rows to the DataTable, making sure to mark the row as inserted, updated or deleted.
DataRow dr = dt.NewRow();
dr["your column"] = ...
// Don't forget to add the row to the table!
dt.Rows.Add(dr);
// Once the row is added then go ahead and mark it as deleted, modified or new
dr.Delete()
// or
dr.SetAdded();
// or
dr.SetModified();

It wont work the way you are doing , do like this
using (var con = new SqlConnection(ConnectionStr))
{
con.Open();
var da = new SqlDataAdapter("select * from table", con);
var ds=new DataSet();
da.Fill(ds);
var dt= ds.Tables[0];
// all deleted rows
foreach(DataRow dr in dt.Rows.ToList())
{
if(deleted.ToList().Contains((int)dr["id"]))
{
dr.Delete();
}
//all updated rows
foreach(var poco in updated.ToList()
{
DataRow dr = table.Select("id="+poco.id).FirstOrDefault();
dr["field1]=poco.feild1
....set all updated values
}
//all inserted rows
foreach(var poco in inserted.ToList())
{
var dr= dt.NewRow();
dr["id"]=poco.id;
..set all fields
dt.Rows.Add(dr);
}
}
dt.Accept
da.Update(dt);
}

Related

Unable to Loop datagridview and amend DefaultCellStyle.Format to N0

I have a datagridview that is populated from an sql query. I would like to format the columns that represent a number to N0 (so they have thousand separators), but the method below is not amending the columns.
When I view these columns in the debugger they have a ValueType of Double.
public void DataGridViewFormat(DataGridView dataGrid)
{
foreach (DataGridViewColumn c in dataGrid.Columns)
{
if (c.DefaultCellStyle.Format == "N")
{
c.DefaultCellStyle.Format = "N0";
}
}
}
This is how I am populating the datagridview:
DataTable dt = new DataTable();
SqlCommand command = new SqlCommand(queryString, connection);
command.Parameters.AddWithValue("#ID", int.Parse(comboBox.Text.Split('|')[0]));
SqlDataAdapter da = new SqlDataAdapter(command);
da.Fill(dt);
dataGridView.DataSource = dt;

Getting "This row already belongs to another table & Input array is longer than the number of columns in this table."

if I used finalTable.Rows.Add(row.ItemArray) it gives me this error "Input array is longer than the number of columns in this table."
con.Open();
cmd.Connection = con;
cmd.CommandText = "SELECT CustomerName FROM Customers";
SqlDataAdapter adp = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
adp.Fill(ds);
DataTable finalTable = new DataTable();
//finalTable.TableName = "Customers";
if (ds.Tables.Count > 0)
{
int i = 1;
DataTable firstTable = ds.Tables[0];
//firstTable.TableName = "Customers";
foreach (DataRow row in firstTable.Rows)
{
if (i == 5)
{
firstTable.NewRow();
i = 0;
}
finalTable.Rows.Add(row.ItemArray);
i++;
}
}
Repeater1.DataSource = finalTable;
Repeater1.DataBind();
con.Close();
and if i used this finalTable.Rows.Add(row), it gives me "This row already belongs to another table".
con.Open();
cmd.Connection = con;
cmd.CommandText = "SELECT CustomerName FROM Customers";
SqlDataAdapter adp = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
adp.Fill(ds);
DataTable finalTable = new DataTable();
//finalTable.TableName = "Customers";
if (ds.Tables.Count > 0)
{
int i = 1;
DataTable firstTable = ds.Tables[0];
//firstTable.TableName = "Customers";
foreach (DataRow row in firstTable.Rows)
{
if (i == 5)
{
firstTable.NewRow();
i = 0;
}
finalTable.Rows.Add(row);
i++;
}
}
Repeater1.DataSource = finalTable;
Repeater1.DataBind();
con.Close();
}
don't know how to solve it, any solution please?
below is a method that allow you select data from your database by TSQL (select * from table1 ...) then return as datatable and continue processing (eg , bind table)
This is how
1) built a connection string , If you are developing web apps , go to web.config file add below , change parameter according your SQL environment setup.
<configuration>
<connectionStrings>
<add name="PSDatabaseConnectionString" connectionString="Data Source=YourSQLserverName\SQLEXPRESS;Initial Catalog=YourDatabaseName;Integrated Security=True" providerName="System.Data.SqlClient"/>
</connectionStrings>
....
2) then build a method to accept SQL statement and return multiple rows data as datatable . In below code , you do not need to define your datatable column structure , SQL will dynamic built it based on your SQL select statement
public static DataTable RunSQL_DML_FillDataGrid(string TSQL)
{
string connectionString = ConfigurationManager.ConnectionStrings["PSDatabaseConnectionString"].ConnectionString;
SqlDataAdapter dataAdapter;
SqlConnection conn = new SqlConnection(connectionString);
try
{
// Run TSQL on SQL server
dataAdapter = new SqlDataAdapter(TSQL, connectionString);
// MS Term ' Create a command builder to generate SQL update, insert, and
// delete commands based on selectCommand. These are used to
// update the database.
SqlCommandBuilder commandBuilder = new SqlCommandBuilder(dataAdapter);
// Populate a new data table and return the table.
// MS Term ' Populate a new data table and bind it to the BindingSource.
DataTable table = new DataTable();
table.Locale = System.Globalization.CultureInfo.InvariantCulture;
dataAdapter.Fill(table);
return table;
}
catch
{
return null;
}
}
3) Finally , you can bind your data table to other object ( datagridview , datatable ....) . I do not know what object type is Repeater1 inside your code but if it can accept datatable , then it shall bind correctly using the returned datatable

How to retrieve second resultset from DataReader to Datatable?

I have an sp that brings back two sets of results. I need to put both of these in a datatable and convert them into a datamodel.
How can I get the second set of results?
SqlConnection connection = new SqlConnection(connectionstring);
ce.Database.Initialize(force: false);
connection.Open();
SqlCommand cmd = new SqlCommand("GetJournal", connection);
cmd.CommandType = System.Data.CommandType.StoredProcedure;
SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
var dataTable = new DataTable();
dataTable.Load(reader);
List<Header> headerList = dataTable.AsEnumerable().Select(values =>
new Header
{
HeaderId = values.Field<Int32>("HeaderId").ToString()
}).ToList();
myList1 = headerList;
myList2 = detailList; <_---- I need to populate detail list
Also is naming all of the fields explicitly the most efficient way to load this list? Is there some sort of serialization that I can do instead? I can have tables up to 500 columns
Until the reader is not closed you can load the further tables. If you have multiple results I suggest you to populate a DataSet, which can contain multiple DataTable instances:
public static DataSet ToDataSet(IDataReader reader)
{
DataSet ds = new DataSet();
while (!reader.IsClosed)
{
DataTable dt = new DataTable();
dt.Load(reader);
ds.Tables.Add(dt);
}
return ds;
}

How To Add Value To Specified Column In DataTable with SqlCommandBuilder

Several days ago, I just known about SqlCommandBuilder Class. So, Now i try to do CRUD Operation with SqlDataAdapter.Update(DataTable) Method
I had tried this :
I Have Table Named "Student" with 3 Columns, "idstudent","Name","Class"
//Assume We Have Open SqlConnection
//conn = SqlConnection Variabel
SqlCommand cmd = new SqlCommand("SELECT * FROM Student", conn);
SqlDataAdater da = new SqlDataAdater(cmd);
SqlCommandBuilder cmdBuilder = new SqlCommandBuilder(da);
DataTable dt = new DataTable();
da.Fill(dt);
//Then, I try to insert with SqlDataAdapter.Update(DataTable) Method
dt.Rows.Add('1','AnyName','2');
da.Update(dt);
Finally, My question is how to insert data like below :
dt.Rows.Add
(
'idstudent' => '2',
'Name' => 'Ruka',
'Class' => '3'
);
//Then Finally Update
da.Update(dt);
What i want to do is like Laravel Create() parameters. We say what column we wanted to insert value
I had read about lambda expression but it's not help me to do what i want.
Try this approach
var row = dt.NewRow();
row["idstudent"] = 2;
row["Name"] = "Ruka";
row["Class"] = 3;
dt.Rows.Add(row);
You can also add rows by doing this
dt.Rows.Add(new object[] {"blah", "blah2", "blah3"});

How do I store multiple results from a stored procedure into a dataset?

How do I combine to result sets from a StoredProcedure into one dataset in ASP.NET?
Below is my code in asp.net
SqlDataAdapter adap = new System.Data.SqlClient.SqlDataAdapter("sp_Home_MainBanner_TopStory",con);
adap.SelectCommand.CommandType = CommandType.StoredProcedure;
adap.SelectCommand.Parameters.AddWithValue("#rows", 9);
DataSet DS = new DataSet();
adap.Fill(DS, "Table1");
adap.Fill(DS, "Table2");
GridView1.DataSource = DS.Tables["Table2"];
GridView1.DataBind();
Even if there were two adapters, how could I combine the results into one dataset?
In MS SQL we create a procedure like:
[ create proc procedureName
as
begin
select * from student
select * from test
select * from admin
select * from result
end
]
In C#, we write following code to retrieve these values in a DataSet
{
SqlConnection sqlConn = new SqlConnection("data source=(local);initial catalog=bj001;user id=SA;password=bj");
SqlCommand sqlCmd = new SqlCommand("procedureName", sqlConn);
sqlCmd.CommandType = CommandType.StoredProcedure;
sqlConn.Open();
SqlDataAdapter sda = new SqlDataAdapter(sqlCmd);
DataSet ds = new DataSet();
sda.Fill(ds);
sqlconn.Close();
// Retrieving total stored tables from a common DataSet.
DataTable dt1 = ds.Tables[0];
DataTable dt2 = ds.Tables[1];
DataTable dt3 = ds.Tables[2];
DataTable dt4 = ds.Tables[3];
// To display all rows of a table, we use foreach loop for each DataTable.
foreach (DataRow dr in dt1.Rows)
{
Console.WriteLine("Student Name: "+dr[sName]);
}
}
A DataSet contains Tables. For your above example, if you had two SqlDataAdapters, each calling a stored procedure and stored them like you did above.
adapter1.Fill(DS, "Table1");
adapter2.Fill(DS, "Table2");
This will take the table results from your first query and store it in the DataSet DS as Table1. It will then store another Table (Table2) in the same DataSet. To access these tables you use the following code:
DS.Tables["Table1"] //Or Table2, or whatever you name it during your Fill.
You already have the right process, you just need to look up how a DataSet works and decide how you want to call your information.
IF you want to combine your results into one DataTable however, you will need to iterate through the tables and combine information.
ex:
DataTable combinedTable = new DataTable();
//Create columns
foreach (DataRow row in DS.Tables["Table1"].Rows)
{
//Create rows? Copy information over? Whatever you want to do.
}
try using this:
adapter1.Fill(DS, "Table1, Table2");
this works here so...

Categories