How to properly execute a linked server stored procedure from C# - c#

I want to execute an stored procedure located in a linked server database. Currently, I'm using this in SSMS:
INSERT INTO myTable
EXEC [LINKEDSERVER\LINKED].[Data_Base_Name].[Store].usp_GetInfo 1, 1, NULL, 'H'
This will insert into my Local DB the result data from the Stored procedure located in LINKEDSERVER\LINKED.
I want to be able to do this with a command from C#, is there a proper way to do it?
Thanks!

You could execute SP from DataContext:
using (DataContext ctx = DataContext())
{
int result = ctx.SP_ProcedureName("1", "2", "3");
}
But first you have to add it to DataContext Diagram from your database as you add tables but from "Stored Procedures" folder.
that is more defensive and neat solution. but if you prefer to use raw command line at least use parameterized query for it like this example :
string sqlText = "SELECT columnName FROM Test_Attachments WHERE Project_Id =#PID1 AND [Directory] = #Directory";
SqlCommand myCommand = new SqlCommand(sqlText, SqlConnection);
myCommand.Parameters.AddWithValue("#PID1", 12);
myCommand.Parameters.AddwithValue("#Directory", "testPath");
It is way for avoiding SQL injection to your code.
Also you could use finally block for close connection :
finally
{
command.Connection.Close();
}

Thank you guys for the help. Oleg thanks for your suggestion as well. What I did was this:
qSQL = "INSERT INTO " + tableName + " EXEC [LINKEDSERVER\\LINKED].[Data_Base_Name]." + spName;
using (SqlConnection _connection = new SqlConnection(connectionString))
{
try
{
command = new SqlCommand();
command.Connection = _connection;
command.Connection.Open();
command.CommandText = _qSQL;
command.CommandTimeout = 300; //Because it takes long
SqlTransaction transaction;
transaction = connection.BeginTransaction();
try
{
command.Transaction = _transaction;
command.ExecuteNonQuery();
transaction.Commit();
Debug.WriteLine("Done");
}
catch (SqlException e)
{
Debug.WriteLine("Exception [{0}:{1}]", e.Number, e.Message);
transaction.Rollback();
}
//close connection
command.Connection.Close();
}
catch (SqlException e)
{
command.Connection.Close();
Debug.WriteLine("exception error number: " + e.Number + ": " + e.Message);
}
}
}
If you have any suggestions to improve this let me know.

Related

Using ADO.NET how to insert list of data into SQL?

I have a list off data like
list=[{id:1,name:"ABC",age:12},{id:2,name:"QWE",age:21}]
I want to insert these data into database dynamically.
I googled and found how to insert a particular data. but dont know how to read the list andthen nsert those data.
string connetionString = null;
SqlConnection connection;
SqlCommand command;
string sql = null;
connetionString = "Data Source=source;Initial Catalog=testDB;User ID=ABCD;Password=password";
sql = "INSERT INTO TableName (id,name,age) VALUES('1','ABC',12)";
connection = new SqlConnection(connetionString);
try
{
connection.Open();;
command = new SqlCommand(sql, connection);
command.ExecuteNonQuery();
command.Dispose();
connection.Close();
}
catch (Exception ex)
{
Console.WriteLine("Can not open connection ! ");
}
cnx.Open(); // open cnx
if(List.Count !=0){ // if List isn't empty
for(int i = 0 i < List.Count ;i++)
{
// here he will execute one by one
string myQuery ="insert into TABLE_NAME values ('"+List[i][0]+"','"+List[i][1]+"','"+List[i][3]+"' ");
SqlCommand cmd = new SqlCommand(myQuery,cnx);
cmd.ExecuteNonQuery();
}
}
// i hope it's help you :))

Check if table exists using command

I'm trying to write a method to check if a table exists. I am trying to use the using statement to keep it consistent through my database.
public void checkTableExists()
{
connectionString = #"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\keith_000\Documents\ZuriRubberDressDB.mdf;Integrated Security=True;Connect Timeout=30";
string tblnm = "BasicHours";
string str = "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = " + tblnm + ");";
SqlDataReader myReader = null;
int count = 0;
try
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
using (SqlCommand command = new SqlCommand(str, connection))
{
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
MessageBox.Show("The count is " + count);
myReader = command.ExecuteReader();
while (myReader.Read())
{
count++;
}
myReader.Close();
MessageBox.Show("Table Exists!");
MessageBox.Show("The count is " + count);
}
connection.Close();
}
}
}
catch (SqlException ex)
{
MessageBox.Show("Sql issue");
}
catch (Exception ex)
{
MessageBox.Show("Major issue");
}
if (count > 0)
{
MessageBox.Show("Table exists");
}
else
{
MessageBox.Show("Table doesn't exists");
}
}
It throws an exception when it hits the try block. It catches in the SqlException block.
This is the point where I am learning to interact with databases again. The solution would be good, but more importantly, a brief explanation of where I have need to learn how to improve my code.
Thanks
Keith
Your code fails because when you write directly a query searching for a string value then this value should be enclosed in single quotes like 'BasicHours'.
However there are some improvements to apply to your actual code.
First, you can use a simplified sql command.
Second, you use parameters instead of string concatenations.
SqlCommand cmd = new SqlCommand(#"IF EXISTS(
SELECT 1 FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = #table)
SELECT 1 ELSE SELECT 0", connection);
cmd.Parameters.Add("#table", SqlDbType.NVarChar).Value = tblName;
int exists = (int)cmd.ExecuteScalar();
if(exists == 1)
// Table exists
This command text don't require you to use an SqlDataReader because the query returns just one row with one 'column' and the value of this single cell is either 1 or 0.
A lot less overhead.
A part from this, it is of uttermost importance, that you never build sql queries concatenating strings. This method is well know to cause problems.
The worse is called SQL Injection and could potentially destroy your database or reveal confidential information to hackers. The minor ones are crashes when the string concatenated contains single quotes. Use always a parameterized query.
I have used the following code in my project and worked for me:
try
{
using (con = new SqlConnection(Constr);)
{
con.Open();
string query = $"IF EXISTS (SELECT * FROM sys.tables WHERE name = '{tableName}') SELECT 1 ELSE Select 0;"
Exists = int.Parse(sqlQuery.ExecuteScalar().ToString())==1;
con.Close();
}
}
catch{}
The problem could be the line: string tblnm = "BasicHours";. You table name is a string and should be apostrophed, try this: string tblnm = "'BasicHours'";
Inside catch blocks you could also log exception messages and details.
Thanks for the help on this issue. This is the solution that I'm implemnenting.
public void checkTableExists()
{
connectionString = #"
Data Source=(LocalDB)\MSSQLLocalDB;
AttachDbFilename=C:\Users\keith_000\Documents\ZuriRubberDressDB.mdf;
Integrated Security=True;
Connect Timeout=30";
string tblName = #"BasicHours";
string str = #"IF EXISTS(
SELECT 1 FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = #table)
SELECT 1 ELSE SELECT 0";
try
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
using (SqlCommand command = new SqlCommand(str, connection))
{
connection.Open();
SqlCommand cmd = new SqlCommand(str, connection);
cmd.Parameters.Add("#table", SqlDbType.NVarChar).Value = tblName;
int exists = (int)cmd.ExecuteScalar();
if (exists == 1)
{
MessageBox.Show("Table exists");
}
else
{
MessageBox.Show("Table doesn't exists");
}
connection.Close();
}
}
}
catch (SqlException ex)
{
MessageBox.Show("Sql issue");
}
catch (Exception ex)
{
MessageBox.Show("Major issue");
}
}

Sending several SQL commands in a single transaction

I have a huge list of INSERT INTO ... strings. Currently I run them with:
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
foreach (var commandString in sqlCommandList)
{
SqlCommand command = new SqlCommand(commandString, connection);
command.ExecuteNonQuery();
}
}
I see that each ExecuteNonQuery() also executes commit.
Is there a way to insert all rows in a single transaction (commit in the end)?
The reason I want a single transaction is to make my "inserts" process faster. Will a single transaction also make it quicker?
Its recommended to use SQL transaction in case you are executing Multiple queries in one thread , you can have it like this :
SqlTransaction trans;
try
{
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();
trans = connection.BeginTransaction();
foreach (var commandString in sqlCommandList)
{
SqlCommand command = new SqlCommand(commandString, connection,trans);
command.ExecuteNonQuery();
}
trans.Commit();
}
catch (Exception ex) //error occurred
{
trans.Rollback();
//Handel error
}
You might probably gain some performance by using just one single transaction and command, as follows:
using (SqlConnection connection = new SqlConnection(connectionString))
{
try
{
connection.Open();
using (SqlTransaction trans = connection.BeginTransaction())
{
using (SqlCommand command = new SqlCommand("", connection,trans))
{
command.CommandType = System.Data.CommandType.Text;
foreach (var commandString in sqlCommandList)
{
command.CommandText = commandString;
command.ExecuteNonQuery();
}
}
trans.Commit();
}
}
catch (Exception ex) //error occurred
{
//Handel error
}
}
A little late, but if you are inserting all of the values into the same table, code the SQL insert as "insert into tablex (f1, f2, f3,...) values (#F1,#F2,#F3...)". Create the command and add the parameters #F1..., and then set the Prepare flag on the command. Now as you loop through your list of values to insert, you can set them into the appropriate parameters and then do the ExecuteNonQuery. SQL will pre-parse the command string once, and then use the new parameters each time. This is a bit faster.
Finally, you can execute multiple SQL statements in a single command by appending ';' to each statement, if you must execute the entire string. You can bunch a number of these commands together and make one request to SQL server to execute them.
You can just concatenate the sql and let the server handle it:
using (SqlConnection connection = new SqlConnection(connectionString))
{
string lsSql = string.Empty;
foreach (var commandString in sqlCommandList)
{
lsSql = lsSql + commandString + " ; " + Environment.NewLine;
}
connection.Open();
SqlCommand command = new SqlCommand(lsSql, connection);
command.ExecuteNonQuery();
}
Here is what I use on my daily work, before it a use a foreach for any non-query that I need to run on database. You can see that I'm using the OracleCommand, but if you need you can change to SQL statement
public static void ExecuteDatabaseNonQuery(string command)
{
OracleCommand cmd = new OracleCommand();
cmd.Connection = conn;
OracleTransaction transaction;
transaction = conn.BeginTransaction(IsolationLevel.ReadCommitted);
cmd.Transaction = transaction;
try
{
cmd.CommandText = command;
var update = cmd.ExecuteNonQuery();
transaction.Commit();
Console.WriteLine("{0} rows updated", update);
}
catch (Exception e)
{
transaction.Rollback();
throw new Exception("Error: " + e);
}
}
Note: If theres any uncommited changes on database this method will wait indefinitely
You can use Parallel for each
using (SqlConnection connection = new SqlConnection(connectionString))
{
List<string> sqlCommandList = new List<string>();
connection.Open();
Parallel.ForEach(sqlCommandList, commandString =>
{
SqlCommand command = new SqlCommand(commandString, connection);
command.ExecuteNonQuery();
});
}

How I can Insert Data in the MySQL Database?

I have a ASP.NET Application and a MySQL Database. I want write a Class to insert,delete and show the Data from the database. I have a Connection to the Database but I can't insert data in the database.
My Class insert method:
public string CreateEntry(string Connectionstring, string mitarbeiter)
{
connection = new MySqlConnection(Connectionstring);
try
{
var command = connection.CreateCommand();
command.CommandText = "INSERT INTO tb_mitarbeiter (Vorname) VALUES ('tom')";
connection.Open();
return "Mitarbeiter wurde angelegt";
}
catch (Exception ex)
{
return ex.Message;
}
finally
{
connection.Close();
}
}
The Connectionstring is correct. I don't get a error but there is no data in the database.
My tablename: tb_mitarbeiter
columns: ID and Vorname
You should simply execute the command
....
MySqlCommand command = connection.CreateCommand();
command.CommandText = "INSERT INTO tb_mitarbeiter (Vorname) VALUES ('tom')";
connection.Open();
command.ExecuteNonQuery();
....
I suppose that mitarbeiter is the real value that should be set in the database.
If this is the case remember to use parameters to insert/update your data
MySqlCommand command = connection.CreateCommand();
command.CommandText = "INSERT INTO tb_mitarbeiter (Vorname) VALUES (?name)";
command.Parameters.AddWithValue("?name", mitarbeiter);
connection.Open();
command.ExecuteNonQuery();
You forgot to execute the command by calling command.ExecuteNonQuery(). This is how I would typically do it:
public string CreateEntry(string connectionString, string valueToInsert)
{
var stringToReturn = "";
try
{
using(var connection = new MySqlConnection(connectionString))
{
//Open connection
connection.Open();
//Compose query using sql parameters
var sqlCommand = "INSERT INTO table_name (field_name) VALUES (#valueToInsert)";
//Create mysql command and pass sql query
using(var command = new MySqlCommand(sqlCommand, connection))
{
command.Parameters.AddWithValue("#valueToInsert", valueToInsert);
command.ExecuteNonQuery();
}
stringToReturn ="Success Message";
}
}
catch(exception ex)
{
stringToReturn = "Error Message: " + ex.Message;
}
return stringToReturn;
}
There are a few key things to keep in mind:
Wrap disposable objects with a using. In the case of
MySqlConnection, it will properly close and dispose the connection
when its out of scope.
Use SQL parameters when passing values inside
your query. This will avoid SQL injection and its much more easier
to maintain.
Personally, I like to have one exit point in a
function. In this example, the "stringToReturn" variable holds the
value to return once the function is done executing both
successfully or in case of a failure.
To do a Insert / Update / Delete u should add
connection.Open();
command.ExecuteNonQuery();
For select ()to show data from database use:
connection.Open();
command.ExecuteReader();
{
string MyConnection2 = "datasource=localhost;port=3306;username=root;password=1234";
string Query = "insert into DBname.TableName(id,Name,First_Name,Age,Address) values('" +this.IdTextBox.Text+ "','" +this.NameTextBox.Text+ "','" +this.FirstnameTextBox.Text+ "','" +this.AgeTextBox.Text+ "','" +this.AddressTextBox.Text+ "');";
MySqlConnection MyConn2 = new MySqlConnection(MyConnection2);
MySqlCommand MyCommand2 = new MySqlCommand(Query, MyConn2);
MySqlDataReader MyReader2;
MyConn2.Open();
MyReader2 = MyCommand2.ExecuteReader();
MessageBox.Show("Save Data");
while (MyReader2.Read())
{
}
MyConn2.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
You are not executing the command use SqlCommand.ExecuteNonQuery
try
{
MySqlCommand command = connection.CreateCommand();
command.CommandText = "INSERT INTO tb_mitarbeiter (Vorname) VALUES ('tom')";
connection.Open();
command.ExecuteNonQuery();
return "Mitarbeiter wurde angelegt";
}
catch (Exception ex)
{
return ex.Message;
}
finally
{
connection.Close();
}
You missed to write this:-
....
connection.Open();
command.ExecuteNonQuery();
....
You can also used Sql parameter to prevent Sql Injection
try
{
MySqlCommand command = connection.CreateCommand();
command.CommandText = #"INSERT INTO `tb_mitarbeiter` (`Vorname`) VALUES (#tom)";
command.Parameters.AddWithValue("#tom", tom);
connection.Open();
command.ExecuteNonQuery();
return "Mitarbeiter wurde angelegt";
}
catch (Exception ex)
{
return ex.Message;
}
finally
{
command.Dispose();
command.Close();
connection.Close();
}

database says that it is inserting, but there are no records

I'm sending a command to the database and it is returning that 1 rows are affected, but when i look inside the database, there are no records. I am receiving no errors. I checked to make sure the string was building correctly and it is. Any ideas? I'm not using parameterized queries here, I know. I will later. Here is the code from the database layer:
public int InsertStartTime(certificate cert, DateTime startTime, string lineNumber)
{
string sql = "INSERT INTO checkLog(userID,lineNumber,startTime) VALUES(" +
cert.userID + ", '" + lineNumber + "', '" + startTime + "');";
int result = 0;
try
{
conn.Open();
comm.CommandText = sql;
result = comm.ExecuteNonQuery();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
conn.Close();
}
MessageBox.Show(result.ToString() + " rows affected");
return result;
}
Using an access 2000 db file:
string connStr = #"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|\assets\users.mdb;Persist Security Info=True";
Right click your database file in VS and look at the properties. Is it set to "Copy Always"? By default, visual studio will make a copy of your database for debugging and any changes will be made only to this copy and will not be reflected in the original. You can set it to copy "Never" if you want to work on the "real" database file even in debug mode.
Depending on the database / data provider you are using, your SQL command may not be executing in auto-commit mode.
Try committing your transaction explicitly. Something like this:
conn.Open();
using (var tran = conn.BeginTransaction()) {
comm.Transaction = tran; // Possibly redundant, depending on database.
comm.CommandText = sql;
result = comm.ExecuteNonQuery();
tran.Commit();
}
Nobody else pointed this out so I will. PLEASE DO NOT USE SQL this way. Use parameters. You leave yourself wide open to sql attacks otherwise.
string sql = "INSERT INTO checkLog(userID,lineNumber,startTime) VALUES(#ID, #line, #starttime);
try
{
conn.Open();
comm.CommandText = sql;
comm.Parameters.Add("ID").Value = cert.userID;
comm.Parameters.Add("line").Value = lineNumber ;
comm.Parameters.Add("starttime").Value = startTime ;
result = comm.ExecuteNonQuery();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}

Categories