C# - Inserting DataSet that contains relational DataTables into Sql Server - c#

Hi I have a DataSet in C# which contains 3 DataTables. Two of the tables: SummaryLocal_Bands and SummaryLocal_Averages contain an fk relationship to the pk in the 3rd table: SummaryLocal. The tables in Sql Server have the same structure, columns, relationships, etc as the tables in this DataSet. Lets say I add rows to the DataTables in the DataSet so that they contain data. I then want to Insert their rows into the sql server tables (which contain the same structure as the datatables in the dataset as noted above). How hard is this to accomplish and how do I accomplish it? Or is it smarter to accomplish this another way?

Is seems like you want to persist the changes on your DataTables to it's underlying tables in the database..can't you just make a connection to database and make an insert statement?...
Try creating a method that have the following commands below: (Note: it's just a skeleton of the commands that you need to do, fill them up according to your settings)
string connectionString = "your_connection_string";
SqlConnection con = new SqlConnection(connectionString);
try
{
con.Open();
string query = "insert statement";
using (SqlCommand cmd = new SqlCommand(query, con))
{
cmd.Parameters.AddWithValue("#some_parameter", "value_of_some_parameter");
cmd.ExecuteNonQuery();
}
}
catch (Exception)
{
throw;
}
Or, if your datatables are somehow not connected to a database, you can still use the above method by looping through the contents of your datatable.

Related

Any way to check if data exist in database during an SQL bulk copy

I'm copying some data from one SQL Server database to another SQL Server database.
That works fine, what I need is to check if some data already exists, then not copy it. How can I do that? Any suggestions?
string Source = ConfigurationManager.ConnectionStrings["Db1"].ConnectionString;
string Destination = ConfigurationManager.ConnectionStrings["Db2"].ConnectionString;
using (SqlConnection sourceCon = new SqlConnection(Source))
{
SqlCommand cmd = new SqlCommand("SELECT [Id],[Client] FROM [Db1].[dbo].[Client]", sourceCon);
sourceCon.Open();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
using (SqlConnection destCon = new SqlConnection(Destination))
{
using (SqlBulkCopy bc = new SqlBulkCopy(destCon))
{
bc.DestinationTableName = "Clients";
bc.ColumnMappings.Add("Id", "ClientId");
bc.ColumnMappings.Add("Client", "Client");
destCon.Open();
bc.WriteToServer(rdr);
}
}
}
}
One way to do what you're after would be to bulk-copy into a staging table (a separate table with similar layout), and then perform a conditional insert from the staging table into the real table.
You could also do something similar using a table-valued-parameter instead of SqlBulkCopy, and treat the table-valued-parameter as the staging table.
Copy all tables from your source database to your destination database as temp tables, then run SQL to add the missing record from the temp table to the destination table. The final step to delete the temp tables.
hope that will work for you.
You could make a database link from source db to destination, and run a query to work out which rows would need to transit, but be careful not to drag too much data over the link as it could make the process slow- realistically you only need the. Columns you will use to determine whether a row in the source equals a row in the dest
Typically though it's easier to bulk copy all the data into a temporary table at the destination then use a merge or insert-leftjoin to only insert some data from temporary table to real table
Here's an example of how to insert only some rows that don't already exist:
INSERT INTO real(column1,column2...)
SELECT temp.column1,temp.column2... FROM
temp
LEFT JOIN real ON real.ID = temp.ID
WHERE
real.ID IS NULL
In c# terms it would look like:
new SqlCommand(#"INSERT INTO real(column1,column2...)
SELECT temp.column1,temp.column2... FROM
temp
LEFT JOIN real ON real.ID = temp.ID
WHERE
real.ID IS NULL", conn).ExecuteNonQuery();
You need to run this using a conn connected to your destination database

OLEDB and C# bulk insert for Excel spreadsheet creation

I am using C# to read a SQL stored procedure, put the results of the stored procedure into a C# data table and then reading the data table row by row to build up my "Insert into....values "etc. This creates my Excel spreadsheet with the correct data. However, instead of inserting row by row, is there a way of doing a bulk insert?
Failing that I was thinking of getting the stored procedure to write the results to a permanent table and therefore is there a way of doing an "Insert into ....select from ". When I have tried this in C# the code is unable to find the SQL table name specified "Microsoft database access engine cannot find the object ", what is the correct syntax and where do you specify where/how to access the SQL table?
Thanks
Hi, that link looks like it's using Microsoft.Office.Interop.Excel;
I'm using OLEDB (which i'm now beginning to regret!). So basically i have a C# class that is called from another component. This C# class reads a sql stored procedure, puts the results into a data table. I then set up the table definition using the OLEDBcommand "Insert into ( []) values ("?"). I then define the parameters e.g. cmd.Parameters.Add(columnHeading, OleDbType.VarChar, size) etc. Then for each row i find in the data table i set the cmd.Parameters[i].value = row[i], where parameters[i] is incremented for each column in that row. I then loop round for each data row and set cmd.Parameters[i].value appropriately. As I have to set the cmd.Parameters[i].Value for each row i find in my dataset and then cmd.ExecuteNonQuery();
, this is quite time consuming. So is there a way to bulk insert the data from the data table into the OLEDB command, if not, can i insert the data by referencing a SQL table directly and doing a "insert into..select from"?
You can separate your insert statements with a semicolon and run just 1 command. For instance ...
string sql = "insert into table (col1,col2) values ('row1','row1');"
sql += "insert into table (col1,col2) values ('row2','row2');"
sql += "insert into table (col1,col2) values ('row3','row3');"
SqlConnection conn = new SqlConnection("some connection string");
SqlCommand cmd = new SqlCommand(sql, conn);
conn.Open();
conn.ExecuteNonQuery();
conn.Dispose();
cmd.Dispose();
Or something similar. You are executing all 3 queries with 1 command. This might not work with databases other than SQL Server, but will definitely work with SQL Server.

Data Adapter Vs Sql Command

Which one would be better in executing an insert statement for ms-sql database:
Sql DataAdapter or SQL Command
Object?
Which of them would be better, while inserting only one row and while inserting multiple rows?
A simple example of code usage:
SQL Command
string query = "insert into Table1(col1,col2,col3) values (#value1,#value2,#value3)";
int i;
SqlCommand cmd = new SqlCommand(query, connection);
// add parameters...
cmd.Parameters.Add("#value1",SqlDbType.VarChar).Value=txtBox1.Text;
cmd.Parameters.Add("#value2",SqlDbType.VarChar).Value=txtBox2.Text;
cmd.Parameters.Add("#value3",SqlDbType.VarChar).Value=txtBox3.Text;
cmd.con.open();
i = cmd.ExecuteNonQuery();
cmd.con.close();
SQL Data Adapter
DataRow dr = dsTab.Tables["Table1"].NewRow();
DataSet dsTab = new DataSet("Table1");
SqlDataAdapter adp = new SqlDataAdapter("Select * from Table1", connection);
adp.Fill(dsTab, "Table1");
dr["col1"] = txtBox1.Text;
dr["col2"] = txtBox5.Text;
dr["col3"] = "text";
dsTab.Tables["Table1"].Rows.Add(dr);
SqlCommandBuilder projectBuilder = new SqlCommandBuilder(adp);
DataSet newSet = dsTab.GetChanges(DataRowState.Added);
adp.Update(newSet, "Table1");
Updating a data source is much easier using DataAdapters. It's easier to make changes since you just have to modify the DataSet and call Update.
There is probably no (or very little) difference in the performance between using DataAdapters vs Commands. DataAdapters internally use Connection and Command objects and execute the Commands to perform the actions (such as Fill and Update) that you tell them to do, so it's pretty much the same as using only Command objects.
I would use LinqToSql with a DataSet for single insert and most Database CRUD requests. It is type safe, relatively fast for non compilcated queries such as the one above.
If you have many rows to insert (1000+) and you are using SQL Server 2008 I would use SqlBulkCopy. You can use your DataSet and input into a stored procedure and merge into your destination
For complicated queries I recommend using dapper in conjunction with stored procedures.
I suggest you would have some kind of control on your communication with the database. That means abstracting some code, and for that the CommandBuilder automatically generates CUD statements for you.
What would be even better is if you use that technique together with a typed Dataset. then you have intellisense and compile time check on all your columns

How can I select what columns come in from a DataSet into a DataTable?

Being new to working with Data, I hope I'm asking this properly. How can I select what columns come in from a DataSet into a DataTable? I know I can fill a DataTable by using...
DataTable table = dataSet1.Tables[0];
but this brings in all the columns. How can I fill a DataTable with only certain columns?
I'm using .NET 3.5, C#, and a SQL CE 3.5 single table database.
Thanks.
The DataTable is actually filled via a DataAdapter when the DataSet is created. Once you run your query, the columns in the DataTable are set. But, you can use a DataView to apply an additional filter and a column reduction to a DataTable, but the cost of querying the database and pulling data has already occurred, so you should consider making sure your query doesn't pull back more than you need. MSDN is a great resource.
Of course if you're just now learning this, it bears mentioning that while ADO.NET is important to know foundationally, you should be aware that there's a lot of momentum away from raw ADO.NET lately towards things like Entity Framework. While SQL will never die, nor should it, you're going to have to write a whole lot more plumbing code when using ADO.NET then you would with a nice ORM. Check out these posts for more info.
// Assumes that connection is a valid SqlConnection object.
string queryString = "SELECT CustomerID, CompanyName FROM dbo.Customers";
SqlDataAdapter adapter = new SqlDataAdapter(queryString, connection);
DataSet customers = new DataSet();
adapter.Fill(customers, "Customers");
DataTable table = customers.Tables[0];
Instead of "CustomerID, CompanyName" you can put the columns you want to select.
For further learning check this MSDN link.

Update linked tables in MS Access Database with C# programatically

I have two Access 2003 databases (fooDb and barDb). There are four tables in fooDb that are linked to tables in barDb.
Two questions:
How do I update the table contents (linked tables in fooDb should be synchronized with the table contents in barDb)
How do I re-link the table to a different barDb using ADO.NET
I googled but didn't get any helpful results. What I found out is how to accomplish this in VB(6) and DAO, but I need a solution for C#.
Here is my solution to relinking DAO tables using C#.
My application uses a central MS Access database and 8 actual databases that are linked in.
The central database is stored locally to my C# app but the application allows for the 8 data databases to be located elsewhere. On startup, my C# app relinks DAO tables in the central database based on app.config settings.
Aside note, this database structure is the result of my app originally being a MS Access App which I ported to VB6. I am currently converting my app to C#. I could have moved off MS Access in VB6 or C# but it is a very easy to use desktop DB solution.
In the central database, I created a table called linkedtables with three columns TableName, LinkedTableName and DatabaseName.
On App start, I call this routine
Common.RelinkDAOTables(Properties.Settings.Default.DRC_Data
, Properties.Settings.Default.DRC_LinkedTables
, "SELECT * FROM LinkedTables");
Default.DRC_Data - Current folder of central access DB
Default.DRC_LinkedTables - Current folder of 8 data databases
Here is code does the actual relinking of the DAO Tables in C#
public static void RelinkDAOTables(string MDBfile, string filepath, string sql)
{
DataTable linkedTables = TableFromMDB(MDBfile, sql);
dao.DBEngine DBE = new dao.DBEngine();
dao.Database DB = DBE.OpenDatabase(MDBfile, false, false, "");
foreach (DataRow row in linkedTables.Rows)
{
dao.TableDef table = DB.TableDefs[row["Name"].ToString()];
table.Connect = string.Format(";DATABASE={0}{1} ;TABLE={2}", filepath, row["database"], row["LinkedName"]);
table.RefreshLink();
}
}
Additional code written to fetch data from a access database and return it as a DataTable
public static DataTable TableFromOleDB(string Connectstring, string Sql)
{
try
{
OleDbConnection conn = new OleDbConnection(Connectstring);
conn.Open();
OleDbCommand cmd = new OleDbCommand(Sql, conn);
OleDbDataAdapter adapter = new OleDbDataAdapter(cmd);
DataTable table = new DataTable();
adapter.Fill(table);
return table;
}
catch (OleDbException)
{
return null;
}
}
public static DataTable TableFromMDB(string MDBfile, string Sql)
{
return TableFromOleDB(string.Format(sConnectionString, MDBfile), Sql);
}
If you're coding in C#, then Access is not involved, only Jet. So, you can use whatever method you want to access the data and then code the updates.
I've coded this kind of thing in Access many times, and my approach for each table is:
run a query that deletes from fooDB that no longer exist in barDB.
run a query that inserts into fooDB records that are in barDB that do not yet exist in fooDB.
I always use code that writes on-the-fly SQL to update the fooDB table with the data from barDB.
The 3rd one is the hard one. I loop through the fields collection in DBA and write SQL on the fly that would be something like this:
UPDATE table2 INNER JOIN table1 ON table2.ID = table1.ID
SET table2.field1=table1.field1
WHERE (table2.field1 & "") <> (table1.field1 & "")
For numeric fields you'd have to use your available SQL dialect's function for converting Null to zero. Running Jet SQL, I'd use Nz(), of course, but that doesn't work via ODBC. Not sure if it will work with OLEDB, though.
In any event, the point is to issue a bunch of column-by-column SQL updates instead of trying to do it row by row, which will be much less efficient.

Categories