I can't seem to find why this function doesn't insert records into the database. :(
I get no error messages or whatsoever, just nothing in the database.
EDIT: this is how my query looks now .. still nothing ..
connection.Open();
XmlNodeList nodeItem = rssDoc.SelectNodes("/edno23/posts/post");
foreach (XmlNode xn in nodeItem)
{
cmd.Parameters.Clear();
msgText = xn["message"].InnerText;
C = xn["user_from"].InnerText;
avatar = xn["user_from_avatar"].InnerText;
string endhash = GetMd5Sum(msgText.ToString());
cmd.Parameters.Add("#endhash",endhash);
cmd.CommandText = "Select * FROM posts Where hash=#endhash";
SqlCeDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
string msgs = reader["hash"].ToString();
if (msgs != endhash || msgs == null)
{
sql = "INSERT INTO posts([user],msg,avatar,[date],hash) VALUES(#username,#messige,#userpic,#thedate,#hash)";
cmd.CommandText = sql;
cmd.Parameters.Add("#username", C);
cmd.Parameters.Add("#messige", msgText.ToString());
cmd.Parameters.Add("#userpic", avatar.ToString());
cmd.Parameters.Add("#thedate", dt);
cmd.Parameters.Add("#hash", endhash);
cmd.ExecuteNonQuery();// executes query
adapter.Update(data);// saves the changes
}
}
reader.Close();
}
connection.Close();
Does nodeItem actually have any items in it? If not, the contents of the foreach loop aren't being executed.
What's the adapter and data being used for? The queries and updates seem be done via other commands and readers.
What does 'hash' actually contain? If it's a hash, why are you hashing the content of the hash inside the while loop? If not, why is it being compared against a hash in the query SELECT * FROM posts WHERE hash = #endhash?
Won't closing the connection before the end of the while loop invalidate the reader used to control the loop?
Lots of things going on here...
You are using the command 'cmd' to loop over records with a datareader, and then using the same 'cmd' command inside the while statement to execute an insert statement. You declared another command 'cmdAdd' before but don't seem to use it anywhere; is that what you intended to use for the insert statement?
You also close your data connection inside the while loop that iterates over your datareader. You are only going to read one record and then close the connection to your database that way; if your conditional for inserting is not met, you're not going to write anything to the database.
EDIT:
You really should open and close the connection to the database outside the foreach on the xmlnodes. If you have 10 nodes to loop over, the db connection is going to be opened and closed 10 times (well, connection pooling will probably prevent that, but still...)
You are also loading the entire 'posts' table into a dataset for seemingly no reason. You're not changing any of the values in the dataset yet you are calling an update on it repeatedly (at "save teh shanges"). If the 'posts' table is even remotely large, this is going to suck a lot of memory for no reason (on a handheld device, no less).
Is anything returned from "Select * FROM posts Where hash=#endhash"?
If not, nothing inside the while loop matters....
Why are you closing the Database Connection inside the while loop?
The code you posted should throw an exception when you try to call cmd.ExecuteNonQuery() with an unopen DB connection object.
SqlCeCommand.ExecuteNonQuery() method returns the number of rows affected.
Why don't you check whether it is returning 1 or not in the debugger as shown below?
int rowsAffectedCount = cmd.ExecuteNonQuery();
Hope it helps :-)
You've got some issues with not implementing "using" blocks. I've added some to your inner code below. The blocks for the connection and select command are more wishful thinking on my part. I hope you're doing the same with the data adapter.
using (var connection = new SqlCeConnection(connectionString))
{
connection.Open();
var nodeItem = rssDoc.SelectNodes("/edno23/posts/post");
foreach (XmlNode xn in nodeItem)
{
using (
var selectCommand =
new SqlCeCommand(
"Select * FROM posts Where hash=#endhash",
connection))
{
var msgText = xn["message"].InnerText;
var c = xn["user_from"].InnerText;
var avatar = xn["user_from_avatar"].InnerText;
var endhash = GetMd5Sum(msgText);
selectCommand.Parameters.Add("#endhash", endhash);
selectCommand.CommandText =
"Select * FROM posts Where hash=#endhash";
using (var reader = selectCommand.ExecuteReader())
{
while (reader.Read())
{
var msgs = reader["hash"].ToString();
if (msgs == endhash && msgs != null)
{
continue;
}
const string COMMAND_TEXT =
"INSERT INTO posts([user],msg,avatar,[date],hash) VALUES(#username,#messige,#userpic,#thedate,#hash)";
using (
var insertCommand =
new SqlCeCommand(
COMMAND_TEXT, connection))
{
insertCommand.Parameters.Add("#username", c);
insertCommand.Parameters.Add(
"#messige", msgText);
insertCommand.Parameters.Add(
"#userpic", avatar);
insertCommand.Parameters.Add("#thedate", dt);
insertCommand.Parameters.Add(
"#hash", endhash);
insertCommand.ExecuteNonQuery();
// executes query
}
adapter.Update(data); // saves teh changes
}
reader.Close();
}
}
}
connection.Close();
}
Of course with the additional nesting, parts should be broken out as separate methods.
I suspect your problem is that you're trying to reuse the same SqlCeCommand instances.
Try making a new SqlCeCommand within the while loop. Also, you can use the using statement to close your data objects.
Why are you calling adapter.Update(data) since you're not changing the DataSet at all? I suspect you want to call adapter.Fill(data). The Update method will save any changes in the DataSet to the database.
How to debug programs: http://www.drpaulcarter.com/cs/debug.php
Seriously, can you post some more information about where it's working? Does it work if you use SQL Server Express instead of SQL CE? If so, can you break out SQL Profiler and take a look at the SQL commands being executed?
Related
I am new to Visual C# programming language and recently i was trying to make a application that is supposed to insert into a local database of users some data but every times my code runs and the insertion works fine the database does not update.This is the code that i am using
try
{
cn.Open();
SqlCommand insert = new SqlCommand();
insert.CommandText = "insert into Clienti (Nume,Prenume,Parola,Email) values(#Nume,#Prenume,#Parola,#Email)";
insert.Connection = cn;
insert.Parameters.AddWithValue("#Nume", register_nume.Text);
insert.Parameters.AddWithValue("#Prenume", register_prenume.Text);
insert.Parameters.AddWithValue("#Parola", register_password.Text);
insert.Parameters.AddWithValue("#Email", register_email.Text);
insert.ExecuteNonQuery();
SqlDataReader reader = insert.ExecuteReader();
while (reader.Read()) { }
MessageBox.Show("Added succesfully");
}
catch (Exception ex)
{
MessageBox.Show(""+ex);
}
I already tried the property Copy to output and it doesn't seems to work.
I am sorry for any grammar mistakes that i made,I would be grateful for any help.
insert.ExecuteNonQuery();
SqlDataReader reader = insert.ExecuteReader();
while (reader.Read()) { }
You only need the ExecuteNonQuery, it will run the INSERT. You need to use ExecuteReader instead only when you're running a statement that produces result sets (eg. SELECT). So it should be:
insert.ExecuteNonQuery();
Its because you have to now read the database using a select statement, you cant use an INSERT SQL statement to read.
You could add the following immediately after your insert.
using(var selectCmd = new SqlCommand("SELECT Nume,Prenume,Parola,Email FROM Clienti WHERE Nume = #Nume", cn))
{
selectCmd.Parameters.AddWithValue("#Nume", register_nume.Text);
using(SqlDataReader reader = selectCmd.ExecuteReader())
{
while (reader.Read()) { }
}
}
That said if you want to know IF the row was inserted or how many records were inserted ExecuteNonQuery returns the number of rows affected. You could change that part of the code like this:
var recordsAffected = insert.ExecuteNonQuery();
if(recordsAffected > 0)
MessageBox.Show("Added succesfully");
else
MessageBox.Show("Nothing happened");
Although in this particular case it would not make sense because if nothing was inserted it would probably be caused by an Exception.
Some side notes
Always wrap types that implement IDisposable in using blocks (see code above as example). It ensures that resources are always released as soon as you are done with them even if an Exception is thrown.
Never swallow Exceptions! Either recover from one and log it or do not catch it at all. If you swallow it you will never know if/why your code broke.
This part of your code is preparing the SQL command that you are running
cn.Open();
SqlCommand insert = new SqlCommand();
insert.CommandText = "insert into Clienti (Nume,Prenume,Parola,Email) values(#Nume,#Prenume,#Parola,#Email)";
insert.Connection = cn;
insert.Parameters.AddWithValue("#Nume", register_nume.Text);
insert.Parameters.AddWithValue("#Prenume", register_prenume.Text);
insert.Parameters.AddWithValue("#Parola", register_password.Text);
insert.Parameters.AddWithValue("#Email", register_email.Text);
The SQL command that your code is running, is an INSERT statement, which only adds a new record to your table.
This statement runs the command that you setup earlier:
insert.ExecuteNonQuery();
If I understand correctly, here you are trying to read the data from the table again:
SqlDataReader reader = insert.ExecuteReader();
while (reader.Read()) { }
Problem is, your command is NOT set for reading. To read data, you need to use a SELECT statement. Something like this:
insert.CommandText = "SELECT Nume,Prenume,Parola,Email from Clienti" ;
So, to read the data after executing the insert, you should do this:
insert.CommandText = "SELECT Nume,Prenume,Parola,Email from Clienti" ;
SqlDataReader reader = insert.ExecuteReader();
while (reader.Read()) { }
You ar executing 2 times the query:
insert.ExecuteNonQuery();
SqlDataReader reader = insert.ExecuteReader();
Try to get the affected rows
int rows = insert.ExecuteNonQuery();
I would suggest creating a stored procedure in your database and just execute the SP.
It's always better to execute SP from code and leave the SQL programming in the DB.
Before you mark this question as a duplicate, here is the tricky part I don't understand. This error is sporadic, I believe the code is correct and it's always working and I'm handling the possible mistakes with an if else condition inside the Reader part. Here is the code:
public static Tuple<int, string> GetIDAndString(string term)
{
try
{
using (SqlConnection con = GetConnection())
using (cmd = new SqlCommand())
using (myReader)
{
int ID = 0;
string status = string.Empty;
cmd.Connection = con;
con.Open();
cmd.CommandText = #"SELECT t.TableID, t.Status
FROM Table t WITH (NOLOCK) /* I know NOLOCK is not causing the mistake as far as I know */
WHERE t.Term = #term";
cmd.Parameters.AddWithValue("#term", term);
myReader = cmd.ExecuteReader();
while(myReader.Read())
{
ID = myReader.IsDBNull(0) ? 0 : myReader.GetInt32(0);
status = myReader.IsDBNull(1) ? string.Empty : myReader.GetString(1).Trim();
}
myReader.Close();
return new Tuple<int, string>(ID, status);
}
}
catch (Exception)
{
throw;
}
}
I know I should be using a class instead of a Tuple, but I can't change that existing code and as you can see. So the main problem is that in the production server there was a Index out of bounds array exception in that method but I can't identify what's the problem.
Even if the term is not found in the query, the myReader will not enter and I'll return the ID = 0, status = string.Empty. Sometimes when I'm debugging code and working on the develpment server, my code starts to crash everywhere, showing me exceptions where is tested code and I have to reopen the solution to avoid that (I haven't found a solution to that, not even cleaning the solution).
So I hope someone have experience with something like that in a production server. I don't have specifications to the production server so I don't know anything about the server.
First you don't need the try/catch block, you don't do anything with it. After that don't share SqlDataReader in the class, this could bring problems and probably the problem comes from this. You are overwriting the value of ID and Status all the time in your while. Probably a good idea will be to call Top 1 on your query and order it by with correct field. Also there is no need to Dispose() the SqlCommand, the Constructor of SqlCommand is calling SupressFinalization().
Why this problem can happen: Imagine your query returns 1000 records with TableID and Status column and you are entering the while loop. In this moment some other user is going in your application and executing another method which overwrites the SqlDataReader and return 5 records with only one column. On the next iteration of you while loop you will receive your exception. Because of that you should never define your Readers as static for the whole class. Static variables are shared between all of application users.
public static Tuple<int, string> GetIDAndString(string term)
{
int ID = 0;
string status = string.Empty;
using (SqlConnection con = GetConnection())
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
con.Open();
cmd.CommandText = #"SELECT t.TableID, t.Status
FROM Table t WITH (NOLOCK) /* I know NOLOCK is not causing the mistake as far as I know */
WHERE t.Term = #term";
cmd.Parameters.AddWithValue("#term", term);
using(SqlDataReader myReader = cmd.ExecuteReader())
{
while(myReader.Read())
{
ID = myReader.IsDBNull(0) ? 0 : myReader.GetInt32(0);
status = myReader.IsDBNull(1) ? string.Empty : myReader.GetString(1).Trim();
}
}
}
return new Tuple<int, string>(ID, status);
}
this probably happens when you do ID = myReader.IsDBNull(0) ? 0 : myReader.GetInt32(0); or status = myReader.IsDBNull(1) ? string.Empty : myReader.GetString(1).Trim(); because the result set does not conform to your expectations. You should add logging of the reader's row before actually reading it, might help you pinpoint the issue
I guess the problem is caused by the myReader field which I suppose is static. If you look at the SqlDataReader (I suppose that's the field's type) documentation at https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader(v=vs.110).aspx, you'll find that instance methods are not thread safe, hence you must synchronize access to that field.
using (myReader) captures the value that the reader had at that time and disposes that later. It does not remember the variable. This has to be so as you can see from this example: using (Random() ? myReader : null). Clearly, the C# language will not reexecute that expression at dispose time. It runs it just once.
So you're disposing some old/other reader.
In case you are sharing objects between threads (maybe using static variables) this trivially is a race condition. Don't do that. Use locals. There is no need/advantage to use static variables here.
I have the following code:
SqlConnection connection1, connection2;
SqlCommand command1, command2;
SqlDataReader reader1, reader2;
using (connection1 = new SqlConnection("connection string here"))
{
using (command1 = new SqlCommand(#"SELECT * FROM [SERVER1].[DATABASE1].[TABLE1] WHERE COL1 = #COL1 AND COL2 = #COL2", connection1))
{
command1.Parameters.Add("#COL1", SqlDbType.VarChar, 255).Value = TextBox1.Text;
command1.Parameters.Add("#COL2", SqlDbType.VarChar, 255).Value = TextBox2.Text;
connection1.Open();
using (reader1 = command1.ExecuteReader())
{
while (reader1.Read())
{
int COL3Index = reader1.GetOrdinal("COL3");
Console.Write("### LOOP 1 ###");
Console.Write(reader1.GetDouble(COL3Index));
using (connection2 = new SqlConnection("same connection string here"))
{
using (command2 = new SqlCommand(#"SELECT * FROM [SERVER1].[DATABASE1].[TABLE2] WHERE COL1 = #COL1", connection1))
{
command2.Parameters.Add("#COL1", SqlDbType.Float).Value = reader1.GetDouble(COL3Index);
connection2.Open();
using (reader2 = command2.ExecuteReader())
{
while (reader2.Read())
{
int COL2Index = reader2.GetOrdinal("COL2");
Console.Write("### LOOP 2 ###");
Console.Write(reader2.GetDouble(COL2Index));
}
}
}
}
}
}
}
}
Basically 2 of everything, I will be needing to do this 5 times, i.e. loop within loop within loop within loop within loop...
The first loop on its own works, but the second one does not work and gives the following error:
There is already an open DataReader associated with this Command which
must be closed first.
on the line:
using (reader2 = command2.ExecuteReader())
How can I get this to work as I need to embed loops
This is the definition of Select N+1 and should be avoided if possible. I would recommend using something like Entity Framework and eagerly loading the child values.
If not possible to avoid, loop though your entire reader1 results, assign to a local collection, close reader1, and then iterate through the local collection and load based on the local values.
You have no reason to open the connection twice if you have MARS enabled to the same database/connection string. This can be done by adding "MultipleActiveResultSets=True" to your connection string.
Additionally, You can use a DataAdapter to load the data into a DataSet/DataTable and then query the DataSet. However, this assumes that your tables aren't too big that you can load them into memory, otherwise an ORM would be a better option.
An ORM solution such as LINQ-to-SQL or LINQ-to-Entities via Entity Framework (as mentioned in Mike Cole's answer) could really help you out here so you don't need to worry about writing these queries and handling the connections. Instead you just rely on a DataContext to handle the connections.
I have a MySql table from which I fetch data to my C# application. Randomly some data are inserted in this table form another source. I want to fetch those data continuously in my C# application. My DB connection and select query are following :
string connection = "Server=localhost;Database=intel;Uid=root;Pwd=";
MySqlConnection dbcon = new MySqlConnection(connection);
MySqlCommand selectData;
dbcon.Open();
selectData = dbcon.CreateCommand();
selectData.CommandText = "SELECT user_id, user_name,user_type FROM win_user ORDER BY user_id ASC ";
MySqlDataReader rdr = selectData.ExecuteReader();
I want to execute my select query unit it get any data.
if
Get data = null
execute my select query again
else
Get data = data
execute my next code
I think it can be happen with while loop, but I dont know how ? Can any onk help me ?
What you want to do sounds odd but, to answer the question as asked, you can use a loop like so:
MySqlDataReader rdr = selectData.ExecuteReader();
// Check whether the result set is empty.
while (!rdr.HasRows)
{
rdr.Close();
// Pause before trying again if appropriate.
rdr = selectData.ExecuteReader();
}
while (rdr.Read())
{
// Read data here.
}
use this
If(rdr.HasRows)
{
rdr.Read();
// do your logic
}
rdr.Close();
use rdr.Read() only when you have some data in datareader object.
if you simply want to read values without checking null than use this
while (rdr.Read())
{
// do logic
}
rdr.Close();
this loop runs as many times as no of rows exist in your select query result.
Replaces Question: Update multiple rows into SQL table
Here's a Code Snippet to update an exam results set.
DB structure is as given, but I can submit Stored Procedures for inclusion (Which are a pain to modify, so I save that until the end.)
The question: Is there a better way using SQL server v 2005.,net 2.0 ?
string update = #"UPDATE dbo.STUDENTAnswers
SET ANSWER=#answer
WHERE StudentID =#ID and QuestionNum =#qnum";
SqlCommand updateCommand = new SqlCommand( update, conn );
conn.Open();
string uid = Session["uid"].ToString();
for (int i= tempStart; i <= tempEnd; i++)
{
updateCommand.Parameters.Clear();
updateCommand.Parameters.AddWithValue("#ID",uid);
updateCommand.Parameters.AddWithValue("#qnum",i);
updateCommand.Parameters.AddWithValue("#answer", Request.Form[i.ToString()]);
try
{
updateCommand.ExecuteNonQuery();
}
catch { }
}
A few things stand out:
You don't show where the SqlConnection is instantiated, so it's not clear that you're disposing it properly.
You shouldn't be swallowing exceptions in the loop - better to handle them in a top level exception handler.
You're instantiating new parameters on each iteration through the loop - you could just reuse the parameters.
Putting this together it could look something like the following (if you don't want to use a transaction, i.e. don't care if some but not all updates succeed):
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
using (SqlCommand updateCommand = new SqlCommand(update, conn))
{
string uid = Session["uid"].ToString();
updateCommand.Parameters.AddWithValue("#ID", uid);
updateCommand.Parameters.AddWithValue("#qnum", i);
updateCommand.Parameters.Add("#answer", System.Data.SqlDbType.VarChar);
for (int i = tempStart; i <= tempEnd; i++)
{
updateCommand.Parameters["#answer"] = Request.Form[i.ToString()];
updateCommand.ExecuteNonQuery();
}
}
}
Or to use a transaction to ensure all or nothing:
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
using (SqlTransaction transaction = conn.BeginTransaction())
{
using (SqlCommand updateCommand = new SqlCommand(update, conn, transaction))
{
string uid = Session["uid"].ToString();
updateCommand.Parameters.AddWithValue("#ID", uid);
updateCommand.Parameters.AddWithValue("#qnum", i);
updateCommand.Parameters.Add("#answer", System.Data.SqlDbType.VarChar);
for (int i = tempStart; i <= tempEnd; i++)
{
updateCommand.Parameters["#answer"] = Request.Form[i.ToString()];
updateCommand.ExecuteNonQuery();
}
transaction.Commit();
}
} // Transaction will be disposed and rolled back here if an exception is thrown
}
Finally, another problem is that you are mixing UI code (e.g. Request.Form) with data access code. It would be more modular and testable to separate these - e.g. by splitting your application into UI, Business Logic and Data Access layers.
For 30 updates I think you're on the right track, although the comment about the need for a using around updateCommand is correct.
We've found the best performing way to do bulk updates (>100 rows) is via the SqlBulkCopy class to a temporary table followed by a stored procedure call to populate the live table.
An issue I see is when you are opening your connection.
I would at least before every update call the open and then close the connection after the update.
If your loop takes time to execute you will have your connection open for a long time.
It is a good rule to never open your command until you need it.
You can bulk insert using OpenXML. Create an xml document containing all your questions and answers and use that to insert the values.
Edit: If you stick with your current solution, I would at least wrap your SqlConnection and SqlCommand in a using block to make sure they get disposed.
emit a single update that goes against a values table:
UPDATE s SET ANSWER=a FROM dbo.STUDENTAnswers s JOIN (
SELECT 1 as q, 'answer1' as a
UNION ALL SELECT 2, 'answer2' -- etc...
) x ON s.QuestionNum=x.q AND StudentID=#ID
so you just put this together like this:
using(SqlCommand updateCommand = new SqlCommand()) {
updateCommand.CommandType = CommandType.Text;
updateCommand.Connection = conn;
if (cn.State != ConnectionState.Open) conn.Open();
StringBuilder sb = new StringBuilder("UPDATE s SET ANSWER=a FROM dbo.STUDENTAnswers s JOIN (");
string fmt = "SELECT {0} as q, #A{0} as a";
for(int i=tempStart; i<tempEnd; i++) {
sb.AppendFormat(fmt, i);
fmt=" UNION ALL SELECT {0},#A{0}";
updateCommand.Parameters.AddWithValue("#A"+i.ToString(), Request.Form[i.ToString()]);
}
sb.Append(") x ON s.QuestionNum=x.q AND StudentID=#ID");
updateCommand.CommandText = sb.ToString();
updateCommand.Parameters.AddWithValue("#ID", uid);
updateCommand.ExecuteNonQuery();
}
This has the advantages of being an all other nothing operation (like if you'd wrapped several updates in a transaction) and will run faster since:
The table and associated indexes are looked at/updated once
You only pay for the latency between your application and the database server once, rather than on each update