Strange behaviour of merge clause - c#

nice people! I am stuck at one problem here and really need your help. I have a Winforms application, which has a few tabs. It connects to MS SQL Server 2008 DB and shows us a DataGridView on the first tab where we
connect to the DB:
private void button_ConnectDB_Click(object sender, EventArgs e)
{
if (sqlConnection == null || sqlConnection.State != ConnectionState.Open)
sqlConnection = new SqlConnection(connectionString);
sqlConnection.Open();
try
{
dataAdapter = new SqlDataAdapter(queryStringUsers, sqlConnection);
SetConnectDBObjects();
SetConnectDBButtons();
}
catch
{
ShowUnableToConnect();
return;
}
}
and have some info from DB:
private void button_SpecAcc_Click(object sender, EventArgs e)
{
dataGridView1.DataSource = this.usersBindingSource;
LoadData(ref dataAdapter, ref clientDataSet, TAB_USERS);
dataGridView1.ReadOnly = false;
},
where LoadData is actually:
private void LoadData(ref SqlDataAdapter dataAdapter, ref clientDataSet dataset, string table)
{ dataAdapter.Fill(dataset, table); }
I have the dataAdapter connected straight to SQL Server, so its configured automatically (all operations, like INSERT, UPDATE, DELETE also). And everything worked just fine (could connect to DB, make any operations, save it (via Apply button, which uses adapter"s Update method)), until Ive decided to make another tab.
Another tab should get me the info (several rows) from other place (some ext device I have connected with), get it into DataTable and MERGE with other rows from the DB. Did it all on this tab following this tutorial: website.
When I try to MERGE some row I can see in my DB nice and good UPDATE, BUT in my first tab (on the form) I can see TWO different rows (one, as if it wasn"t touched and second - as if it was updated). I supposed it''s something with Refreshing (tried Refreshing of GridView, didn"t help), or some other element"s Refresh (but which one?...), and I still can not find it.
Would appreciate any help... Thanks

Dealt with it through creating temp dataset, editing it (via DataRows) and getting it into a database. Thanks all the watchers :)

Related

Why does windows form freeze when it loads in C#?

I am new to C# and I am using windows forms.
I am building an application and I am facing a strange serious problem when Form loads.
I have 2 forms:
Form1 has a button_Edit and DataGridView
Form2 has a DataGridView1 and DataGridView2
As it is shown in the code and the screen shot, in Form1 when I select a row in DataGridView then click on Button_Edit the Order number and DateTime values in DataGridView on Form1 are passed to Form2 and then Form2 opens up.
Now in Form2 Load event there is a SQL query which takes Order number and DateTime to bring the relevant order details and then fill DataGridView1 and DataGridView2 in Form2.
In Form1:
Form2 frm2 = new Form2();
private void button_Edit_Click(object sender, EventArgs e)
{
frm2._ Order_Number= Convert.ToInt32(dataGridView1.SelectedRows[0].Cells[0].Value);
frm2._ Date_Time= Convert.ToDateTime(dataGridView1.SelectedRows[0].Cells[4].Value);
frm2.ShowDialog();
}
In Form2:
SqlConnection MyConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString);
SqlCommand MyCommand = new SqlCommand();
DataTable DataTable = new DataTable();
SqlDataAdapter Sql_Data_Adapter = new SqlDataAdapter();
int Order_Number;
DateTime Date_Time;
int i;
double Sum;
int RowIndex;
public int _ Order_Number
{
set { Order_Number = value; }
}
public DateTime _ Date_Time
{
set { Date_Time = value; }
}
private void Form2_Load(object sender, EventArgs e)
{
DataTable.Rows.Clear();
DataTable.Columns.Clear();
MyConnection.Open();
MyCommand.CommandText = "SELECT * FROM Customer_Order_Details WHERE Order_Number = #OrderNumber and Date_Time = #DateTime ";
MyCommand.Connection = MyConnection;
MyCommand.Parameters.Add("#OrderNumber", SqlDbType.Int).Value = Order_Number;
MyCommand.Parameters.Add("#DateTime", SqlDbType.DateTime).Value = Date_Time;
Sql_Data_Adapter.SelectCommand = MyCommand;
Sql_Data_Adapter.Fill(DataTable);
MyCommand.Parameters.Clear();
MyConnection.Close();
dataGridView1.Rows.Clear();
dataGridView2.Rows[0].Cells[1].Value = 0;
Sum = 0;
//////////////FILL THE ORDER INTO DATAGRIDVIEW1///////////
RowIndex = DataTable.Rows.Count - 1;
for (i = 0; i <= RowIndex; i++)
{
dataGridView1.Rows.Add(DataTable.Rows[i][2], DataTable.Rows[i][3], DataTable.Rows[i][4]);
// Calculate the total:
Sum = Convert.ToDouble(DataTable.Rows[i][4]) + Sum;
}
dataGridView2.Rows[0].Cells[1].Value = sum;
}
The issue:
This code works fine and as I wanted and DataGridView1 & DataGridView2 in Form2 are filled with the right details and it works fine when Form2 loads.
However, sometimes Form2 freezes after filling both DataGridView1 & DataGridView2 when Form2 loads and I can not do anything until I kill the Application using Task manager.
This issue happens sometimes and it is unpredictable. I really don’t know what is wrong.
I had a look here , here and here but non of those questions related to my issue. Note that I already use try catch and it does not throw anything because the form freezes. This freeze behavior occurs in the release mode I mean after I build EXE file then I install it in a PC and here the issue happens.
Has anyone got any idea why this bad unpredictable behavior occurs?
Is there anything that I should change in my code?
I will be very happy to listen to any new ideas/solutions no matter how small it is, it will be very beneficial.
Thank you
Do SQL work on another thread. Check out Asynchronous call.
BeginInvoke
I suggest using Async versions of Open (connecting to RDBMS) and ExecuteReader (query executing):
con.Open() -> await con.OpenAsync()
q.ExecuteReader() -> await q.ExecuteReaderAsync()
this easy substitution makes UI responsible (it doesn't freeze) while connecting to RDBMS and executing the query.
// do not forget to mark Form2_Load method as async
private async void Form2_Load(object sender, EventArgs e) {
// Do not share the connection - create it and dispose for each call
using (SqlConnection con = new SqlConnection(...)) {
await con.OpenAsync();
string sql =
#"SELECT *
FROM Customer_Order_Details
WHERE Order_Number = #OrderNumber
AND Date_Time = #DateTime";
// do not share command/query as well
using (SqlCommand q = new SqlCommand(sql, con)) {
q.Parameters.Add("#OrderNumber", SqlDbType.Int).Value = Order_Number;
q.Parameters.Add("#DateTime", SqlDbType.DateTime).Value = Date_Time;
dataGridView1.Rows.Clear();
dataGridView2.Rows[0].Cells[1].Value = 0;
Sum = 0;
// We actually don't want any sql adapter:
// all we have to do is to fetach data from cursor and append it to grids
using (var reader = await q.ExecuteReaderAsync()) {
while (reader.Read()) {
dataGridView1.Rows.Add(reader[2], reader[3], reader[4]);
Sum += Convert.ToDouble(reader[4]);
}
}
}
}
}
as said the code snippet you gave us isn't well written. You should use more Try/Catch Statements to prevent crashs and freezes on your programm. This will help you to find bugs even while running the Programm in release. Furthermore you have many options to solve your problem.
1:
Try to start Form2 in a second thread, then only your form2 will freeze until your sql finishes
2:
As mentioned before try to use asyncronous calls to avoid freeze time of handling the sql
3:
There is no direct need of a SQL Database/Connection. You could also use a Collection and create objects defined of your Products (like cola) and them bind them through the database. (If you are interested in i could show you a example)
The best way for you would be:
Add some Try/Catch Statements and get familiar with it, get familiar with Systems.Thread and try to start your form2 in a new thread if this doenst work go to step 2 and add asynchronus calls
In the end i would like to tell you, that namen your Forms "Form1" and "Form2" isn't nice could maybe you like to change it.

sync data grid view

i have data grid view that its data source is a data table in form in c#,
how can i make it read table from database continuously
i mean if my program running in many computers in same network and connected with same database , if computer 1 add row to the database its appears automatically in computer 2 without clicking any button to refresh.
void load()
{
c.connect("sel_dep");
c.com.CommandType = CommandType.StoredProcedure;
SqlDataAdapter da=new SqlDataAdapter (c.com);
DataTable dt = new DataTable();
c.open();
int last = 0;
while (true)
{
if (dt.Rows.Count > 0)
dt.Rows.Clear();
da.Fill(dt);
dd = dt;
if (dt.Rows.Count != last)
{
last = dt.Rows.Count;
this.Invoke((MethodInvoker)delegate { dataGridView1.DataSource = dt; dataGridView1.SelectedRows[0].Selected = true; label1.Text = dataGridView1.RowCount.ToString(); });
}
}
c.close();
}
private void Form3_Load(object sender, EventArgs e)
{
aa = new Thread(() => { load(); });
aa.Start();
}
this is my tray
If you are using Winforms to create the desktop application, you would not need timer.
Simply drag and drop Timer control from the Toolbox on your form, in design mode.
' The form load should be altered as below
private void Form3_Load(object sender, EventArgs e)
{
' Assume the Timer control is named as 'oTimer'
oTimer.Enabled = true;
oTimer.Interval = 60000; ' In Milliseconds, equates to 1 minute
oTimer.Start();
}
Create the Tick event for the Timer. This event would be fired each time the interval elapses.
private void oTimer_Tick(object sender, EventArgs e)
{
<Call your function to initiate/refresh the DataGrid.DataSource within this event>
}
In order to further understand how the Timer class works, refer Timer Class (System.Windows.Forms).
Also refer to Stackoverlow question Winforms Timer for Dummies with plenty of resources and tips to master the Timer control.
If you're using Sql Server you can have a look at Query Notifications, more specifically at SqlDependency class. It can be used to get notifications from sql server, when data changes, into your desktop application
Built upon the Service Broker infrastructure, query notifications
allow applications to be notified when data has changed. This feature
is particularly useful for applications that provide a cache of
information from a database, such as a Web application, and need to be
notified when the source data is changed.

whats the use of data adapter

Can anyone explain why an SqlDataAdapter is used in the following code? The code is working fine without this adapter.
Also, why do we use DataAdapter? Please help me to understand this DataAdapter usage.
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
private void button1_Click(object sender, EventArgs e)
{
try
{
SqlConnection con = new SqlConnection("Data Source=.....\\SQLEXPRESS;Initial Catalog=......;Integrated Security=True");
con.Open();
SqlDataAdapter da =new SqlDataAdapter(); // Why use `SqlDataAdapter` here?
SqlCommand sc = new SqlCommand("insert into bhargavc values(" + textBox1.Text + "," + textBox2.Text + ");", con);
var o = sc.ExecuteNonQuery();
MessageBox.Show(o + "record to be inserted");
con.Close();
}
catch (Exception)
{
MessageBox.Show("error in the code");
}
}
private void button2_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
}
Data adapter works like a mediator between the database and the dataset. However, a data adapter cant store data. It just gives data from the database to the dataset.
For Example:
A water pipe is used to bring water from a source (well, pond, etc.) to a destination. However, the pipe isn't used to store water. In the same way, a data adapter (like a water pipe) sends data from the database to a dataset.
This should give a clearer understanding about data adapters.
A data adapter is used to read data from a data reader into a DataTable or a DataSet.
As you are not reading any data from the database in this code, the data adapter is completely superflous.
As a side note, you should use parameters instead of putting values directly into the query. Your code is totally open to SQL injection attacks.
There are several reasons to use a DataAdapter:
You can't fill a DataSet without one.
When the adapter completes its .Fill() method, it will close the connection for you; you don't have to explicitly call the .Close() method on your connection object. Although, it is still good practice to.
In your case, it isn't necessary to have one though. But, if you did want to use one, the implementation would look like this:
SqlDataAdapter da = new SqlDataAdapter();
DataSet ds = new DataSet();
da.Fill(ds);
From there, there are further actions that you can take on the ds object like exporting to Excel via Interop, filling a DataGridView or even updating a database table.
To fill either dataset or datatable
You don't have to close your SQL connection explicitly like .Close()

Use SqlDataAdapter to fill a table in a dataset with a new name, code don't run completely and no error

As you see, my code (it's in myform_load), when I run project, it continues to line 1. Just not run other lines after that. I got no error, but the code doesn't run completely. After it come to line one, myform is shown. Where is the problem?
SqlDataAdapter userSharj_history;
private void myform_Load(object sender, EventArgs e)
{
using (SqlConnection con = new SqlConnection(connectionString))
{
con.Open();
using (userSharj_history = new SqlDataAdapter(String.Format("SELECT * FROM users_sharj WHERE user_id = {0} AND datetime BETWEEN '{1}%' AND '{2}%'", user_id, az_tarikh_globalizationDateTimePicker1.Text, ta_tarikh_globalizationDateTimePicker1.Text), con))
{
1. userSharj_history.Fill(nan_DataSet, "sharjes");
2. gridControl1.DataSource = nan_DataSet.Tables["sharjes"];
}
con.Close();
}
view_btn.Focus();
}
The Query string is fine. I tested it in GUI Query Builder.
I use this dataset in my main form that call this form and there is no table in it with the name sharjes.
Either check the Output window or enable reporting of all exceptions. Visual Studio will not inform you about many exceptions by default.
Go to menu Debug --> Exceptions... and then tick Thrown for Common language runtime Exceptions and click OK. Run your code again and see if it throws an exception now.

DBConcurrencyException in SQL Database

He everybody,
Recently I've started a project that needs a lot of data. So much in fact it cannot be stored in the runtime memory.
I've been looking for solutions to this problem and have chosen for the use of a SQL databases.
I found a tutorial explaining how they work and recreated it myself. It makes sure your physical database and virtual dataset stay in sync by using a dataAdapter to update the database;
(FYI the tutorial can be found here: http://www.homeandlearn.co.uk/csharp/csharp_s12p1.html);
However when expanding a tutorial i came across an error i cant explain namely: DBConcurrencyException.
When i run the program all functionality works, i can add a row and delete a row. But when i try to do both in the same execution (order = add then delete) the error comes up.
It describes that zero of the one expected records were affected by the DeleteCommand.
The following code snippits is what i used:
Initialization:
private void Form1_Load(object sender, EventArgs e)
{
con = new SqlConnection();
ds1 = new DataSet();
con.ConnectionString = "Data Source=.\\SQLEXPRESS;AttachDbFilename=C:\\<Private>\\MyWorkers.mdf;Integrated Security=True;Connect Timeout=30;User Instance=True";
con.Open();
string sql = "SELECT * From tblWorkers";
da = new SqlDataAdapter(sql, con);
da.Fill(ds1, "Workers");
NavigateRecords();
MaxRows = ds1.Tables["Workers"].Rows.Count;
updateIndicator();
con.Close();
//con.Dispose();
}
(Note: I commented out the directory for privacy reasons);
The addition of a row is done as followed:
private void btnSave_Click(object sender, EventArgs e)
{
SqlCommandBuilder cb = new SqlCommandBuilder(da);
DataRow dRow = ds1.Tables["Workers"].NewRow();
dRow[1] = textBox1.Text;
dRow[2] = textBox2.Text;
dRow[3] = textBox3.Text;
ds1.Tables["Workers"].Rows.Add(dRow);
MaxRows = MaxRows + 1;
inc = MaxRows - 1;
da.Update(ds1, "Workers");
MessageBox.Show("Entry Added");
}
When deleting a row this code is executed:
private void btnDelete_Click(object sender, EventArgs e)
{
SqlCommandBuilder cb = new SqlCommandBuilder(da);
ds1.Tables["Workers"].Rows[inc].Delete();
MaxRows--;
inc = 0;
NavigateRecords();
da.Update(ds1, "Workers");
MessageBox.Show("Record Deleted");
}
The NavigateRecord() method and setIndicator() method are not relevant in this question since they are GUI elements.
Thanks in advance everybody!
I came across this question statement while looking for a way to prevent SQL Server from locking an entire record (I want it to lock by field / column value instead) and noticed that no answer had been given, so here ya go if anyone else runs into this problem:
OP didn't actually ask a question, only stated what the problem was; so here's the answer to the question that wasn't asked "How do I prevent Database Concurrency Violations?":
Database Concurrency Violations (in this case) are preventable by making a decision as to which data gets to go in to the database. Most people elect to take the approach that 'last in wins'. So, in your handling of operations using the TableAdapter, put the Update in a Try/Catch and during Catch for DBConcurrencyException just make sure you do a quick Fill, then change whatever you were supposed to be changing, and then do the Update. Works every time.

Categories