Using C# to Insert lines from an array into SQL Server 2012 - c#

Earlier I posted this code but it was much more messy, parts were commented out, and I was using concatenation to INSERT to the database. I was told to clean it up, challenged to use parameters, and ask more concise questions. With that being said, the connection to the database was given to me with mostly pseudo-code with some direct commands.
1) Is my Try-Catch set up correctly?
2) "server = LOCALHOST" is underlined in red, it says it can't convert 'string' to System.Data.SqlClient.SqlConnection'
3) "Database" and "Lab1" are underlined saying it doesn't exist in current context? What does this mean?
4) "Trusted_connection" and "yes" have the same error message as #3.
5) I'm not sure what to put after "cmd.Connection = " which is why it's commented out and has a question mark after it.
6) Is my varname1.Close(); in the right spot? I feel like it makes sense for it to actually go between the last 2 closing brackets?
7) In the Catch "SqlException" is underlined and the error says "The type or namespace SqlException could not be found". I found a try-catch from another user on stackoverflow that asked the question and someone responded with the catch set up like that so I copied it.
8) I'm trying to figure out parameters, Is mine set up correctly? All I have is 1 textbox in which the user inputs data and it enters into an array. "Name" is the name of the attribute of the student in the database, and I just made up #Name as a variable? I found a parameter example from another user also on stackoverflow and kind of made match mine.
public static int counter = 0;
protected void btnDisplay_Click(object sender, EventArgs e)
{
try
{
System.Data.SqlClient.SqlConnection varname1 = new System.Data.SqlClient.SqlConnection();
varname1 = "server = LOCALHOST";
Database = Lab1;
Trusted_connection = yes;
varname1.Open();
System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand();
// cmd.Connection = (?)
cmd.CommandText = "Delete From Student";
cmd.ExecuteNonQuery();
for(int i=0; counter >= i; i++)
{
cmd.CommandText = "INSERT INTO Lines (Name) " + "VALUES (#Name)";
cmd.Parameters.AddWithValue("#Name", studentList[i]);
counter++;
}
varname1.Close();
}
catch (SqlException ex)
{
lbl5.Text = "Connection could not be established";
}
}

You need to find a good resource (or a few) and learn how to make proper database calls. Here's one. Here's another, on creating connection strings.
I haven't tested the following, but something like this should work.
using (var conn = new System.Data.SqlClient.SqlConnection("Server=LOCALHOSTDatabase=Lab1;Trusted_Connection=True;"))
{
conn.Open();
using (var cmd = new SqlCommand("Delete From Student", conn))
{
cmd.ExecuteNonQuery();
}
using (var cmd = new SqlCommand("INSERT INTO Lines (Name) VALUES (#Name)", conn))
{
for (int i = 0; counter >= i; i++)
{
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("#Name", studentList[i]);
cmd.ExecuteNonQuery();
}
counter++;
}
}
As for some of your other questions...
#1 - Your try/catch is setup okay.
#6 - Don't bother calling Close() - use a using block
#7 - The exception name looks okay. Do you have using System.Data.SqlClient; at the top of your form? You may be getting an error here because of other lines of code with errors... hard to say.
#8 - That looks fine.

You should have a finally block with your try-catch
Your SQLConnection should be created with the connection string as a parameter. You can't set it equal to a String, it's a SQLConnection.
I don't know where Database and Lab1 are declared but it's obviously not within the scope of your function.
See 3. And yes has no meaning.
cmd.Connection = varName1
You should close your connection in a finally block to ensure it is closed even if an exception is thrown
Have you imported System.Data.SQLClient?
Adding parameters with values will replace #Name in your SQL string with the value you supplied

Related

Capturing RAISERROR in C#

I tried to find a useful answer to this question, but failed (the closest I found was this). I have a C# app calling a stored procedure which uses SQL TRY/CATCH to handle errors. I can replicate the issue with a sample stored procedure like this:
if object_id('dbo.TestSQLError') is not null drop proc dbo.TestSQLError
go
create proc dbo.TestSQLError
as
begin try
select 1 / 0
end try
begin catch
raiserror('Bad tings appen mon', 16, 1)
end catch
then a little dummy program like this:
namespace TestSQLError
{
class Program
{
public const string CONNECTION_STRING = #"data source=localhost\koala; initial catalog=test; integrated security=true;";
static void Main(string[] args)
{
try
{
using (SqlConnection conn = new SqlConnection(CONNECTION_STRING))
{
SqlCommand cmd = new SqlCommand("dbo.TestSQLError", conn) { CommandType = System.Data.CommandType.StoredProcedure };
conn.Open();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
Console.WriteLine(rdr.GetValue(0).ToString());
}
rdr.Close();
}
conn.Close();
}
Console.WriteLine("Everything looks good...");
}
catch (SqlException se)
{
Console.WriteLine("SQL Error: " + se.Message);
throw se;
}
catch (Exception e)
{
Console.WriteLine("Normal Error: " + e.Message);
throw e;
}
Console.ReadLine();
}
}
}
The stored procedure raises an error of level 16 which as far as I've read should be enough to be error-worthy. However control never jumps to the catch block; it just chugs through like nothing went wrong.
I read someone suggest using OUTPUT parameters... which I can do, but it seems like I must be missing something fundamental and simple here. Can anyone help?
UPDATE: It would appear if I use ExecuteNonQuery() the errors propagate just fine. However my use case is a procedure which performs DML and returns data based on that DML. Maybe the answer is "don't do that" but it'd be nice to know if there's a way to simply catch an error when grabbing results.
The reason is because the raise error is after the end of the first result set in the data reader and we’ll only get the error if we call NextResult() on the data reader!
When using a SqlDataReader it will only iterate over the first result
set, which in this case will be the select in the stored procedure
Try and see more details here
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (!rdr.IsClosed())
{
while (rdr.Read())
{
Console.WriteLine(rdr.GetValue(0).ToString());
}
if (!rdr.NextResult())
{
rdr.Close();
}
}
}
I can make three suggestions:
Use CommandType.Text instead of CommandType.StoredProcedure. This may be fixed now, but a number of years ago I found that CommandType.StoredProcedure would always buffer message outputs into batches of about 50, while CommandType.Text would allow the messages to come back to C# right away.
Add a WITH NOWAIT hint to your RAISERROR code.
Don't forget about the FireInfoMessageEventOnUserErrors property. You do want to handle the InfoMessage event.
I'm not sure any of these will solve your problem, but they should give you some direction.

SQL Update statement doesn't update values when adding multiple columns otherwise it does

No exceptions, everything gets executed but the update doesn't happen!
Everything works ok when I have just #JIR parameter but now I added #Paragon and the update doesn't do it's job. No exception whatsoever data passed is OK...
I don't see anything wrong with this query does anyone know what could possibly be going wrong?
private static void InsertJIR(FisDnevni racun)
{
using (OleDbConnection con = new OleDbConnection(RegistarBlagajna.Modul.VezaNaBazu.ConnectionString))
{
try
{
con.Open();
OleDbCommand cmd = new OleDbCommand(#"
UPDATE FisDnevni
SET [JIR] = #JIR,
[Paragon] = #Paragon
WHERE BrojRacuna = #BrojRacuna"
, con);
cmd.Parameters.AddWithValue("#JIR", racun.JIR.Substring(0,37));
cmd.Parameters.AddWithValue("#BrojRacuna", racun.BrojRacuna);
cmd.Parameters.AddWithValue("#Paragon", racun.Paragon);
cmd.ExecuteNonQuery();
con.Close();
}
catch (Exception)
{
throw;
}
}
}
This is a good old problem - ensure the query parameters in OleDbParameter are declared in proper order like this:
using (OleDbConnection con = new OleDbConnection(RegistarBlagajna.Modul.VezaNaBazu.ConnectionString))
{
try
{
con.Open();
using (OleDbCommand cmd = new OleDbCommand(#"UPDATE FisDnevni SET [JIR] = #JIR, [Paragon] = #Paragon WHERE BrojRacuna = #BrojRacuna", con)
{
cmd.Parameters.AddWithValue("#JIR", racun.JIR.Substring(0,37));
// this must be the second parameter instead of third one
cmd.Parameters.AddWithValue("#Paragon", racun.Paragon);
cmd.Parameters.AddWithValue("#BrojRacuna", racun.BrojRacuna);
cmd.ExecuteNonQuery();
con.Close();
}
}
catch (Exception)
{
throw;
}
}
Note that OLE DB .NET Provider doesn't recognize named parameters for OleDbCommand when CommandType is set to Text, but it apparently does recognize the parameter order, hence as long as they're passed in proper order, it'll accepted as query parameter.
Related issue:
how to update a table using oledb parameters?
maybe i've just never used it, but why is there an # here?
OleDbCommand(#"
i also havent worked with C# in a while but is multi-line concatenation possible without a + or something?
thirdly why are you using [] on these column names? i don't see any special characters or spaces.
this post is sounding a lot more dikkish than i mean it to be, im not trying, just legit curious

Update existing database entries C# VS2010

I'm using Visual Studio 2010 to create a Win Form in c#. It has a handful of Comboboxes, and textboxes that the user can fill out and then submit to an Access DB. My issue comes in when I try to update existing entries. I load an existing entry, make my changes and click update. I do not get any system errors, my connection to the DB is successful, but no changes are actually made to the data. Am I completely missing something? Thanks in advance for any help or insight.
Here is the code for the update button:
private void updateButton_Click_1(object sender, EventArgs e)
{
{
OleDbConnection conn = new OleDbConnection();
conn.ConnectionString = #"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|\servicereq1.mdb";
OleDbCommand cmd = new OleDbCommand("UPDATE servicereq SET DateLogged = #datelogged, LoggedBy = #loggedby, Function = #function, [Other Impacts] = #summary, Account = #earningsaccount, [From] = #from, [To] = #to, Description = #description, Fixer = #fixer, [Time Estimate] = #timeestimate, [Actual Start] = #actualstart, [Actual Finish] = #actualfinish, [Actual Time] = #actualtime, [Programs/Forms] = #programsforms, Comments = #comments, [Retest Date] = #requestdate, Tester = #tester, Status = #status, [Problem In Environment] = #problemfoundin, [Code In Environment] = #codein WHERE (ServiceRequestNumber = #servreq)");
cmd.Connection = conn;
conn.Open();
if (conn.State == ConnectionState.Open)
{
cmd.Parameters.AddWithValue("#servreq", serviceRequestNumberTextBox.Text);
cmd.Parameters.AddWithValue("#datelogged", dateLoggedTextBox.Text);
cmd.Parameters.AddWithValue("#loggedby", loggedByComboBox.Text);
cmd.Parameters.AddWithValue("#problemfoundin", problem_In_EnvironmentComboBox.Text);
cmd.Parameters.AddWithValue("#function", functionTextBox.Text);
cmd.Parameters.AddWithValue("#summary", other_ImpactsTextBox.Text);
cmd.Parameters.AddWithValue("#earningsaccount", accountTextBox.Text);
cmd.Parameters.AddWithValue("#from", fromTextBox.Text);
cmd.Parameters.AddWithValue("#to", toTextBox.Text);
cmd.Parameters.AddWithValue("#status", statusComboBox.Text);
cmd.Parameters.AddWithValue("#description", descriptionTextBox.Text);
cmd.Parameters.AddWithValue("#fixer", fixerComboBox.Text);
cmd.Parameters.AddWithValue("#codein", code_In_EnvironmentComboBox.Text);
cmd.Parameters.AddWithValue("#programsforms", programs_FormsTextBox.Text);
cmd.Parameters.AddWithValue("#timeestimate", time_EstimateTextBox.Text);
cmd.Parameters.AddWithValue("#actualstart", actual_StartTextBox.Text);
cmd.Parameters.AddWithValue("#actualfinish", actual_FinishTextBox.Text);
cmd.Parameters.AddWithValue("#actualtime", actual_TimeTextBox.Text);
cmd.Parameters.AddWithValue("#requestdate", retest_DateTextBox.Text);
cmd.Parameters.AddWithValue("#tester", testerComboBox.Text);
cmd.Parameters.AddWithValue("#comments", commentsTextBox.Text);
try
{
cmd.ExecuteNonQuery();
MessageBox.Show("Form Updated Successfully");
conn.Close();
}
catch (OleDbException ex)
{
MessageBox.Show(ex.Message);
conn.Close();
}
}
else
{
MessageBox.Show("Connection Failed");
}
}
}
You shouldn't put your database parameters within quotes - they are evaluated as plain text instead of parameters if you do. There is no row where ServiceRequestNumber equals the literal string '#servreq', so nothing is updated.
Also, DataCommands don't pull in local variables as parameters - they must be explicitly added to the DataCommand object (cmd in this case). The reason you aren't getting any errors when you remove your parameter-adding code is because, as stated above, the query doesn't expect any parameters.
Also, the way parameters are being added in the code you removed is strange to say the least. This is much more normal, and significantly easier to read:
cmd.Paramaters.AddWithValue("#paramName", paramData);
//or
cmd.Parameters.Add(new OleDbParameter("#paramName", paramData));
After spending a little more time editing and moving code around, I stumbled on the fact that your parameters must be in the same order in the query as they are when you bind values to them. After making syntactical changes suggested by JoFlash Studios and putting my parameters in the correct order, I was able to make edits to existing data in my form.

Update SQL Server on button click

I am trying to update a particular column of a SQL Server table using my aspx page on button click event. My code is:
if (AutoMan.Text == "Auto Mode")
{
var x = "1";
var y = DateTime.Now.ToString();
var z = "1";
using (SqlConnection con = new SqlConnection(#"Data Source=localhost.\SQLEXPRESS;Initial Catalog=MCAS;Integrated Security=SSPI;"))
{
con.Open();
try
{
using (SqlCommand cmd = new SqlCommand("UPDATE AutoManLog SET AutoMan = #data, Time = #data1", con))
{
cmd.Parameters.AddWithValue("#data1", y);
cmd.Parameters.AddWithValue("#data", x);
cmd.ExecuteNonQuery();
}
}
catch (Exception Ex)
{
Response.Write("Unable To Save Data. Error - " + Ex.Message);
}
con.Close();
}
Data in the database is not updating. I Can't see any error messages.
in this query:
"UPDATE AutoManLog SET AutoMan = #data, Time = #data1"
Time is a preserved name for sql server; so use it as [Time] will be solve the problem,
if there isn't another problem exist.
I copy-pasted your code and it works just as is; your parameters are correct, and your statement is correct.
Your possible issues are:
AutoMan.Text does not equal "Auto Man" -- make sure they are equal
Any error occurring (database connection, table doesn't exist, etc.), but something is obstructing your Response.Write output, not making you able to see the output -- take out the try-catch, and let the debugger catch errors so you can trace it better

Getting timeout errors with SqlTransaction on same table

public TransImport()
{
ConnString = ConfigurationManager.ConnectionStrings["Connection"].ConnectionString;
SqlConnection conn_new;
SqlCommand command_serial_new;
SqlConnection conn;
SqlCommand command_serial;
SqlTransaction InsertUpdateSerialNumbers;
conn = new SqlConnection(ConnString);
command_serial = conn.CreateCommand();
conn_new = new SqlConnection(ConnString);
command_serial_new = conn_new.CreateCommand();
command_serial_new.CommandText = "SELECT 1 FROM YSL00 WHERE SERLNMBR = #slnr";
var p = new SqlParameter("#slnr", SqlDbType.NVarChar, 50);
command_serial_new.Parameters.Add(p);
//Here you will start reading flat file to get serialnumber.
InsertUpdateSerialNumbers = conn.BeginTransaction();
while (!headerFileReader.EndOfStream)
{
headerRow = headerFileReader.ReadLine();
if (CheckSerialNumber(headerFields[0].Trim()))
DisplayMessage("Good serialnumber"); //this function is not copied here.
}
InsertUpdateSerialNumbers.Commit();
}
private Boolean CheckSerialNumber(string SerialNumber)
{
command_serial_new.Parameters["#slnr"].Value = SerialNumber;
try
{
var itExists = Convert.ToInt32(command_serial_new.ExecuteScalar()) > 0;
if (!itExists)
{
command_serial.Transaction = InsertUpdateSerialNumbers;
command_serial.CommandText = "INSERT INTO YSL00([Manifest_Number],[PONUMBER],[ITEMNMBR],[SERLNMBR]"
+ "VALUES ('" + Manifest + "','" + PONr + "','" + itemNumber + "','" + serialNr + "')";
var insertStatus = command_serial.ExecuteNonQuery();
return true;
}
}
catch (Exception ex)
{
LogException(ex, "Error in CheckSerialNumber =>"+ command_serial_new.CommandText.ToString());
}
return false;
}
I get error "Timeout expired. The timeout period elapsed prior to completion of the operation or server is not responding".
The CheckSerialNumber function also does an insert to YSL00 (the same table where I had executescalar. See code above).
As I mentioned earlier there are 1000s of line in a flat file that I read and update YSL000 table.
Note that I have two separate sqlcommands and also two separate connections to handle this. Reason is with sqltransaction it doesn't let me to query on the same table. I think timeout may be happening because of this?
Thanks for reading. Please suggest
Update 1: Since I have not pasted entire code, I want to mention that dispose is done using below code in the program.
if (conn != null)
{
conn.Close();
conn.Dispose();
}
if (conn_new != null)
{
conn_new.Close();
conn_new.Dispose();
}
you can increase the time out of your SqlConnection object.
you can do this with your ConnString:
string connStr = "Data Source=(local);Initial Catalog=AdventureWorks;Integrated
Security=SSPI;Connection Timeout=300";
I think default isolation level - read commited - is preventing your 'CheckSerialNumber' method from being effective. Command_serial_new will not take into consideration rows inserted in your loop - this might lead to some troubles. To be honest I would also look for some deadlock. Perhaps command_serial_new is actually completely blocked by the other transaction.
To start off:
Set command_serial_new query as:
SELECT 1 FROM YSL00 WITH (NOLOCK) WHERE SERLNMBR = #slnr
Think about using lower isolation level to query inserted rows as well (set it to read uncommited).
Close your connections and transactions.
Use just one SqlConnection - you don't need two of them.
Many of the objects you are using implement IDisposable, and you should be wrapping them with using statements. Without these using statements, .NET won't necessarily get rid of your objects until an undetermined time when the garbage collector runs, and could block subsequent queries if it's still holding a transaction open somewhere.
So for example, you'll need to wrap your connections with using statements:
using (conn_new = new SqlConnection(ConnString)) {
...
If I am not mistaken you need to merge the file content with the table content.
For this purpose I would recommend you
Copy the file content in to a temporary table (see temporary tables and BulkInsert)
Use command MERGE (http://msdn.microsoft.com/en-us/library/bb510625.aspx) to merge the temporary table content with the original table

Categories

Resources