Update same column in several sql tables using C# - c#

The Scenario:
I have a mobile phone comparing asp.net website which displays deals of various networks. The data about the deals we receive from the networks is in an excel sheet. We import the data from the excel sheets to the tables of each network in our database. Now, the data that we receive is not consistent for every network, as in, a network may name give the phone name as 'curve 8250' and another may give it as '8250 curve' and another might give it as '8250curve'.
Now, we have another module which allows the user to view the deals of a particular handset available on all the networks. To make this module work, what we need to do id make sure that the phone names are consistent for all the networks.
For this, I am planning to make a module for the webadmin which displays the phone names(probably in a gridview) from all the network tables, and the webmaster could edit the phone names so as to make them consistent. The retrieval of the distinct column names from all the tables was easy, and that is done.
The Problem:
Now, the real part is that how can we program the module so that it updates the particular column values in all the network tables. The schema of each table is exactly the same.
Edit: I always forget to add something :# . I know it can be done the hard way, in code behind, running a loop. But is there any simpler, hassle free way out there? like some datacontrol that would make life a bit easier in this situation?
Update:
I tried doing this using code behind. I made a gridview and displayed the data using item templates, and also provided a textbox in a second template. Then on a button click, I'm running this code:
protected void Button1_Click(object sender, EventArgs e)
{
SqlConnection con = new SqlConnection(ConfigurationSettings.AppSettings[0].ToString());
foreach(GridViewRow gvr in GridView1.Rows)
{
TextBox tb = (TextBox)gvr.FindControl("New Value");
Label lbl = (Label)gvr.FindControl("Old Value");
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
if (lbl.Text != tb.Text)
{
try //updation if primary key constraint is not broken
{
con.Open();
cmd.CommandText = myupdatecommand; /*this is not the actual command that I'm passing, the command I'm passing does contain the values lbl.Text & tb.Text. This is just to make it a better read.*/
cmd.ExecuteNonQuery();
}
catch (SqlException sqe)
{
if (sqe.ErrorCode == -2146232060)//if primary key constraint is broken
{
try
{
//delete the row from the table that contains only unique phone names
cmd.CommandText = deletecommand;
cmd.ExecuteNonQuery();
}
catch { }
}
}
finally
{
con.Close();
}
//Update table2
try //only updation as here the phone name is not a primary key
{
con.Open();
cmd.CommandText = updatetable2;
cmd.ExecuteNonQuery();
}
catch
{
}
finally
{
con.Close();
}
.
.
.
//similarily update rest of the tables
.
.
.
Response.Redirect(Request.Url.ToString());
}
}
When I run the this code, everything happens smoothly, but when we update more than one row in the grid at a time, the updation only occurs for the first edited row, the other edited rows are remaining the same.
I know it must be a very small thing that I'm missing out on here, but I'm not able to proceed further :(
Any help on the matter is highly appreciated. Thanks in advance!
PS- I'm using ASP.Net 3.5, with c# as code behind, and SQL Server 2005 as back-end.

OK, I'm going to assume you are using LINQ-to-Sql, but in theory, it shuoldn't matter, the basic principle is the same.
You will need a collection of connection string, one for each each database. Presumably you already have this.
using (TransactionScope scope = new TransactionScope())
{
foreach (var connStr in listOfConnStr)
{
using (var db = new MyDataContext(connStr);
{
// do update here.
}
}
}
That's pretty much it.
You could pass the "do update here" part in as a lambda function.

To be honest, I'm now embarrassed to answer my own question.
The problem was just that I had mistakenly put the Response.Redirect(Request.Url.ToString());
inside the if loop which itself is inside the foreach loop.
When will I stop doing silly mistakes :|

Related

Dynamic SQL issue - C# Forms (Datagridview)

I am currently trying to update my DataGridView to my database. I want to be able to update it with the enter key. But I am getting this error:
"Dynamic SQL generation for the UpdateCommand is not supported against a SelectCommand that does not return any key column information."
Here is a picture of the code(as well its below in code snippet)
Some of the code
Here is how the Datagridview is loaded:
private void RampBoardLoader()
{
SqlConnection connection = new SqlConnection(ConnectionLoader.ConnectionString("Threshold"));
connection.Open();
SqlCommand selectRampBoard = new SqlCommand("Select_Ramp_Data", connection);
selectRampBoard.CommandType = CommandType.StoredProcedure;
selectRampBoard.Parameters.AddWithValue("#DateID", dateTimeRamp.Value.Date);
dt = new DataTable();
dataAdapter = new SqlDataAdapter(selectRampBoard);
dset = new DataSet();
dataAdapter.Fill(dset, "Ramp_Board");
dgvRampBoard.DataSource = dset.Tables[0];
connection.Close();
}
Here is where I'm trying to update the datagridview:
private void dgvRampBoard_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
e.Handled = true;
scb = new SqlCommandBuilder(dataAdapter);
dgvRampBoard.EndEdit();
this.dataAdapter.Update(dset, "Ramp_Board");
}
}
I've been looking around to try to find the answer to this. Every post I see everyone says that you need to make sure your table has a primary key. My table does have a primary key. It has 2 primary keys. "Flight Number" and "DateID". I'm not sure if it's because I have 2 primary keys, if that's why I'm getting this issue.
Attached is image of Database of my stored procedure. You can also see the columns, I have 2 primary keys
Stored Procedure
How to make life easy:
(Note; this only works in a net framework project; the designer has bugs in net core and Microsoft have disabled it. There are tricks you can pull if you want to work in core, but they basically entail using a net framework project to do the editing and a netcore to do the running)
add a dataset type file to your project
open it, right click its surface, choose add tableadapter
Set up your connection
Choose to use stored procedures to get your data
Choose your sprocs (I assume you have one for updating ?)
Name the Fill/GetData methods appropriately (FillByDateId ?)
Save the dataset
Go to a new form
Open DataSources window on View menu, other windows
Drag the node representing your table, onto your form. You should see a grid, binding source, dataset and navigator appear
That's it, you should be able to just run the app now, enter some date Id in the box, hit fill, change the data, hit save..
You can find the code the designer write for you in the normal code behind and in the FormXx.Designer.cs files if you're curious how it works. A tableadaptermanager will call tableadapter.Update(datatable) on "parent, child" order for every table that needs updating. Table adapter's Update uses the InsertCommand, UpdateCommand and DeleteCommand as appropriate to persist each row change according to what the row state is

C# SQL Assistance

I am currently attempting to write a .net 4.6 console app to work with a database, below is the test database structure and I have tried a number of tutorials in order to set about the best way to insert and update the data and what i seem to come up with seems somewhat cumbersome or not particularly manageable.
USE [Test_Table]
GO
INSERT INTO [dbo].[Test_Data]
([Identifier]
,[XDocument]
,[XVersion]
,[XSubVersion]
,[SubmittedBy]
,[SubmissionID]
,[SubmissionDateTime]
,[AssociatedFiles]
,[UpdatedXdocument]
,[DateTimeUpdated]
,[UpdateComments])
VALUES
(<Identifier, nvarchar(20),>
,<XDocument, xml,>
,<XVersion, int,>
,<XSubVersion, int,>
,<SubmittedBy, nvarchar(20),>
,<SubmissionID, nvarchar(20),>
,<SubmissionDateTime, datetime,>
,<AssociatedFiles, nvarchar(max),>
,<UpdatedXdocument, xml,>
,<DateTimeUpdated, datetime,>
,<UpdateComments, nvarchar(10),>)
GO
At the moment i am looking at this tutorial: https://sqlchoice.azurewebsites.net/en-us/sql-server/developer-get-started/csharp/win/step/2.html
However i would really like to know what the best/most professional way in order to insert and update data against this? as it I will seed some columns but then update later on, to date i have not needed to use sql data as yet so would really like to start with a good footing from experienced programmers.
my connection method is this which works great:
SqlConnection _sqlConnection;
SqlDataReader _sqlData;
SqlCommand _sqlCommand;
public bool ConnectToDB()
{
try
{
string conString = $"Data Source={TEST_Config.Database_Host};Initial Catalog={TEST_Config.Database_Name};Integrated Security={TEST_Config.Integrated_Security}";
_sqlConnection = new SqlConnection(conString);
_sqlConnection.Open();
return true;
}
catch(Exception CTDB_EX)
{
log.Info($"Issues Encountered Connecting to the Database: {CTDB_EX.Message}");
if (log.IsDebugEnabled)
{
log.Debug($"STACK_TRACE: {CTDB_EX.StackTrace}");
}
return false;
}
}
After this i ran through a number of tutorials but struggled with larger column sets and handling them in the best way, I then decided to create a class for the columns with getters and setters ie
public string _Identifier {get;set;}
etc etc
but at this point i stalled and decided to look for advice.
Many thanks in advance.
Try to add a .dbml file in your project, using this you could manage all the database related activities with drag and drop database objects. It uses LINQ for all database transaction (select, insert, update, delete).

VSTO Addin Connecting to MSSQL

I have a VSTO addin. Right now I am hard coding two dictionaries for development. They need to persist so I am going to use mssql. I have created the tables and all, so everything is done on that end. But I'm having some trouble getting a few things to work so I have a few questions:
First, is it possible to use Windows Forms in VSTO to create a CRUD form for the database tables? There are 2 tables and they aren't too long.
Next, when connecting with SqlConnection, the example connection strings I am seeing don't make any sense. Here is an example: tmpConn = new SqlConnection("server=(local)\\SQLEXPRESS;Trusted_Connection=yes"); I'm not sure how to make the connection string. Right now my db is a local mssql instance, but in the future it will be hosted on a local network server. It says SQLEXPRESS now, is that the same as mssql? If not how can I change it to mssql? How do I construct the correct string for mssql and how do I authenticate? Is it done in the connection string or somewhere else?
Next to Last, is there an easy way to query a database with 3 columns, ID (PK), domain, and dirname. And place domain and dirname into a dict where domain is the key and dirname the value, the ID is uneeded for this.
Here is what I have so far:
public void retrieveClient(SqlConnection conn)
{
try
{
using (conn)
{
SqlCommand command = new SqlCommand(
"SELECT ClientDirName, ClientEmailDomain FROM ClientTable;",
conn);
conn.Open();
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
string clientDir = reader.GetString(0);
string clientEmail = reader.GetString(1);
clientDict.Add(clientEmail, clientDir);
}
}
else
{
MessageBox.Show("No rows found in ClientTable", "Rows Not Found", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
reader.Close();
}
}
catch (InvalidOperationException ex)
{
MessageBox.Show(String.Format("Exception while accessing ClientTable: {0}", ex), "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
catch (SqlException ex)
{
MessageBox.Show(String.Format("Exception while accessing ClientTable: {0}", ex), "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
And finally, the part where it says string clientDir = reader.GetString(0) and string clientEmail = reader.GetString(1) Will it return the correct values here? The table has 3 values as I said, ID, Dir, and Email. But as you can see my SqlCommand only selects ClientDirName and ClientEmailDomain. Does this mean the GetString() methods will return those with 0 and 1? Or would it be 1 and 2 since ID is 0? I'm not sure how it works, does reader.GetString() base the indexes off the actual table or the SqlCommand?
I also wanted to know if the while (reader.Read()) part will add each row one by one so that my clientDict.Add() would work properly or not.
If it possible to do CRUD with a database with windows forms please give me some guidance or a small example. Other than that I just need my code examined to make sure it's doing what I want. I've been trying to test it but there are a lot of other missing pieces at the moment so I need assistance.
Any assistance would be much appreciated. And if someone could provide a few small example connection strings for both local and network mssql servers that require authentication it would be a huge help. I've been looking everywhere and can't get this working. I've heard EF could do it but I can't find a single example or guide that does what I need. If someone could share one that may help too, if you with EF is the way to go.
Thanks in advance!
You may treat your VSTO based add-in as a regular .Net application. There is no anything specific from the Db perspective. The only difference is that your VSTO assembly is run within the host application (not standalone). So, I'd suggest reading any good book on how to use SQL databases (ADO.NET) in .net applications or use EF (Entity Frameworks) first. It will give you the answer to all your questions.

Delete from database in c#

I'm writing an app in C# WPF with VS10 express.
I have to say I'm a very beginner in C# and VS but I'v searched a lot of examples on Google, I really tried to solve this problem on my own..
I have a local database (mydatabase.sdf) and at the load of my window I fill a table of that database with some data. One of the fields of that table needs a unique value, so I want to put in every load the same data, but I get an error than off course.
I want to delete all the data from the database before I refill, this seems to be so easy but I don't get it working...
I tried
dataset.Tables["mytable"].Clear()
that doesn't work, it seems to be deleting only data from the datagrid (dataTable) but not really from the datastore.
also I tried:
for (int i = 0; i < dataset.Tables["mytable"].Rows.Count; i++)
{
dataset.Tables["mytable"].Rows[i].Delete();
}
this.TableAdapter.Update(this.dataset);
But at startup the dataset.Tables["mytable"].Rows.Count statement returns zero at startup, but if I put in my data I get the "unique-value error".
The only way to get it deleted is to delete it manually from the datagrid and then push an Update button, that really deletes it from the datastore.
It is no option to make that field in the database not-unique because of development reasons.
How can I delete really data from the datastore/database (mydatabase.sdf) in the load of my program??
EDIT
Here is the code how I fill the database with data:
public void FillInternet()
{
klantenTableAdapter1.ClearBeforeFill = false;
string MyConString = "SERVER=myserver;" +
"DATABASE=mydb;" +
"UID=myuid;" +
"PASSWORD=mypass;";
MySqlConnection connection = new MySqlConnection(MyConString);
MySqlCommand command = connection.CreateCommand();
MySqlDataReader Reader;
command.CommandText = "SELECT klantnr, voorletters, roepnaam, achternaam, tussenvoegsel, meisjesnaam, straat, huisnr, subhuisnr, postcode, plaats, telthuis, telmobiel, telwerk, fax, email, geboortedatum FROM klanten ORDER BY klantnr";
connection.Open();
Reader = command.ExecuteReader();
try
{
while (Reader.Read())
{
DataRow newLogRow = dataset1.Tables["klanten"].NewRow();
var thisrow = "";
for (int i = 0; i < Reader.FieldCount; i++)
{
thisrow = Reader.GetValue(i).ToString();
newLogRow[Reader.GetName(i)] = thisrow;
}
dataset1.Tables["klanten"].Rows.Add(newLogRow);
this.klantenTableAdapter1.Update(this.dataset1);
}
connection.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message,"Fout",MessageBoxButton.OK,MessageBoxImage.Error);
}
dataset1.AcceptChanges();
//Fill from internet
//da.Fill(dataset1.klanten);
//Fill from local database
klantenTableAdapter1.Fill(dataset1.klanten);
this.klantenTableAdapter1.Update(this.dataset1);
this.DataContext = dataset1.klanten.DefaultView;
}
ADO.NET uses a "disconnected" recordset model. It keeps a copy of the data in client-side structures (DataSet and DataTable). Updates/inserts/deletions made to the client-side structures need to be pushed back out to the database. You need to read up on ADO.NET to get a basic understanding of this process and to get a sense of the ADO.NET event-model, which will be necessary if you want to do anything that involves typical real-world complications. There are many books written on ADO.NET because it is a feature-rich middle-tier data layer with significant complexities.
For your purposes, you could read up on the ADO.NET Command object and the SQL "delete" command. You will also need to explore how ADO.NET handles autoincrementing primary keys, which is one of the trickiest aspects of the disconnected model.
If the database itself defines an autoincrementing key, you cannot supply that value when inserting new rows unless you turn the auto-increment off temporarily in the back-end. That is not an ADO.NET issue, BTW. That is 100% back-end.
From your other posts, I'm going on the assumption that your database on this too is MySQL. You mention a unique column which typically means an auto-increment column. If you "delete" the entries after you've built them (say starting 1-10), and then try to re-add your next cycle the same 1-10 items, it can choke on you giving you this message. If you add numbers to your table starting with the last one used... see if that helps.

Trying to maintaining a DataSet in WinForm App

I am in the process of converting an in-house web app to a winform app for disconnected reasons and I hit the following snag.
In the Function SaveMe() on the webapp there is the following code on the Person.ascx.vb page -->
//get dataset from session
Dim dsPerson As Data.DataSet = CType(Session.Item("Person" & Me.UniqueID), DataSet)
//if no rows in dataset, add
If dsPerson.Tables(0).Rows.Count = 0 Then
Dim rowPerson As Data.DataRow = dsPerson.Tables(0).NewRow
dsPerson.Tables(0).Rows.Add(FillPersonRow(rowPerson))
Else
//otherwise update
....more code here
The part I am stuck on is how to logically create a dataset on a WinForm app?
Should I just scrape all the fields and throw them into a DataSet? How(this is what I will research/try while waiting for advice from SO)?
EDIT
The Session is getting created/populated in the LoadMe() Sub, like so -->
//load person
Dim dsTemp As Data.DataSet = BLL.Person.GetPerson(PersonID)
//save to session state
Session.Add("Person" & Me.UniqueID, dsTemp)
EDIT
What I am trying to do is create a Form level variable --> private DataSet _personInfo; to hold the DataSet then in my FormPaint(int personID) I call the following:
_personInfo = ConnectBLL.BLL.Person.GetPerson(personID);
I then use that to populate the various fields on the Form.
Next, on btnUpdate_Click() I try the following but to no avail:
void btnUpdate_Click(object sender, EventArgs e)
{
var areChanges = _personInfo.HasChanges();
if (areChanges)
{
var whatChanged = _personInfo.GetChanges();
var confirmChanges =
MessageBox.Show(
"Are you sure you want to make these changes: " +
whatChanged.Tables[0].Rows[0].ItemArray.ToString(), "Confirm Member Info Changes",
MessageBoxButtons.YesNo, MessageBoxIcon.Hand);
if (confirmChanges == DialogResult.Yes)
{
_personInfo.AcceptChanges();
ConnectBLL.BLL.Person.Update(_personInfo);
}
}
FormPaint(HUD.PersonId);
}
I am unclear what I am doing wrong? Am I missing a step?
Thank you
First,
If you want a good explanation of the issue that Jacob raised read the following article...
http://www.knowdotnet.com/articles/datasetmerge.html
And I agree with the others that you seem to be making it harder than it needs to be.
You are not clear what the ConnectBLL class is...is that a custom bizness object or a strongly typed dataset.
To do databinding which will automatically save would be a very long post so in lieu of that here are a couple of links.
http://www.codeguru.com/columns/vb/article.php/c10815
http://support.microsoft.com/kb/313482
http://msdn.microsoft.com/en-us/library/aa984336(VS.71).aspx
Those were the first links I found on google using (step by step instruction on winforms databinding with a strongly typed dataset) as the search string. You might find a better one. The codeguru link looked pretty good. The other to are more thorough at the expense of being more technical.
Best of all...if you can spring for Chris Sells book in winforms development, the chapters on data binding are excellent (along with all of the other chapters.)
http://www.amazon.com/Windows-Forms-Programming-Microsoft-Development/dp/0321267966/ref=sr_1_1?ie=UTF8&qid=1249525202&sr=8-1
Hope this helps.
In that snippet, the DataSet comes from session. When is it set ?
You certainly can use a DataSet in a WinForms application. Is it the databinding, you are having trouble with ?
Your problem is likely here:
if (confirmChanges == DialogResult.Yes)
{
_personInfo.AcceptChanges();
ConnectBLL.BLL.Person.Update(_personInfo);
}
AcceptChanges sets the RowState to Unchanged on all rows that were ready to be updated. Frankly, it'd probably be better to use whatChanged as that'll keep your adapter from having to re-check for changed rows.
if (confirmChanges == DialogResult.Yes)
{
ConnectBLL.BLL.Person.Update(whatChanged);
_personInfo.AcceptChanges();
}

Categories