C# - How to send Insert with #Parameters to Database Connection Class - c#

Having a bit of an issue getting my insert to work properly. When I run the insert all within the same method, it works flawlessly... however when I try to send the Insert statement to my new Connection class (which I will have handle all database requests), I am getting the following error.
Note: I am using C# and Microsoft SQL Server.
System.Data.SqlClient.SqlException (0x80131904): Must declare the scalar variable "#CollectionGroupID".
I believe I am not sending the parameters over, however I am not sure of the best way to do this.
Here's my AddGame method:
public static void AddGame(int gameId)
{
string statement = "INSERT INTO Collection (CollectionGroupID, SharedID, UserID, GameID, Owned, Favorited, WishList, DeletedIndicator, AddUser, AddDate, ModUser, ModDate) VALUES (#CollectionGroupID, #SharedID, #UserID, #GameID, #Owned, #Favorited, #WishList, #DeletedIndicator, #AddUser, #AddDate, #ModUser, #ModDate)";
using (SqlCommand cmd = new SqlCommand())
{
cmd.Parameters.AddWithValue("#CollectionGroupID", "0");
cmd.Parameters.AddWithValue("#SharedID", "0");
cmd.Parameters.AddWithValue("#UserID", "0");
cmd.Parameters.AddWithValue("#GameID", gameId);
cmd.Parameters.AddWithValue("#Owned", "Y");
cmd.Parameters.AddWithValue("#Favorited", "N");
cmd.Parameters.AddWithValue("#WishList", "N");
cmd.Parameters.AddWithValue("#DeletedIndicator", "N");
cmd.Parameters.AddWithValue("#AddUser", "test/admin");
cmd.Parameters.AddWithValue("#AddDate", DateTime.Now);
cmd.Parameters.AddWithValue("#ModUser", "test/admin");
cmd.Parameters.AddWithValue("#ModDate", DateTime.Now);
Connection.Open();
Connection.Statement(statement);
Connection.Close();
}
}
And here is my Statement method in my Connection class
public static void Statement(string sql)
{
Console.WriteLine("Attempting to submit data to the database...");
try
{
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.ExecuteNonQuery();
}
catch (SqlException e)
{
Console.WriteLine(e);
}
}
I feel like perhaps I am overlooking a simple solution. Any help appreciated!
-Travis W.

Command parameter is defined in SqlCommand in your AddGame method
you are passing the raw Sql over to the Statement method and inside the method you are creating another SqlCommand without parameter defined. This is why the parameters are not being passed in.
you should just do
using (SqlConnection connection = new SqlConnection(connectionString))
{
//OR using (SqlConnection connection = Connection.Open())
//If you want to keep your Connection class to avoid having to pass in connection string.
using (SqlCommand cmd = new SqlCommand(statement, connection))
{
...
cmd.ExecuteNonQuery ()
}
}
inside your AddGame method

Related

How to insert data into local database using C#

I am working on my first project using local database on C#. I have searched on internet different code for inserting data, but nothing has worked for me. I am trying different code, the problem that occurs to me is the built in functions they are using doesn't show up in my code. Can someone share the authentic code for inserting, retrieving and deleting in local database ?
The recent code that I have tried, some exception is occurring in SqlCeConnection.
This is my code :
string str="Data Source=(localdb)shop_database;Initial Catalog=shop_database;Integrated Security=True";
SqlCeConnection con = new SqlCeConnection(str);
SqlCeDataAdapter sda = new SqlCeDataAdapter();
SqlCeCommand cmd = con.CreateCommand();
cmd.CommandText = "Insert into Account_details (Account_No,Customer_name,Customer_father_name,Profession,Mobile_No,Office_Address,House_Address,CNIC,Item_name,Item_color,Item_model,Item_engine_NO,Item_chasis_NO,Cash_price,Installment_price,Advance_given,Amount_left,Monthly_Installment,Monthly_Rent,Date_of_giving,Sponsor_name,Sponsor_father_name,Sponsor_profession,Sponsor_Address,Sponsor_CNIC,Sponsor_Mobile_No) values (#Account_No,#Customer_name,#Customer_father_name,#Profession,#Mobile_No,#Office_Address,#House_Address,#CNIC,#Item_name,#Item_color,#Item_model,#Item_engine_NO,#Item_chasis_NO,#Cash_price,#Installment_price,#Advance_given,#Amount_left,#Monthly_Installment,#Monthly_Rent,#Date_of_giving,#Sponsor_name,#Sponsor_father_name,#Sponsor_profession,#Sponsor_Address,#Sponsor_CNIC,#Sponsor_Mobile_No)";
cmd.Parameters.AddWithValue("#Account_No", this.Textbox0.Text);
cmd.Parameters.AddWithValue("#Customer_name", this.Textbox1.Text);
cmd.Parameters.AddWithValue("#Customer_father_name", this.Textbox2.Text);
cmd.Parameters.AddWithValue("#Profession", this.Textbox3.Text);
cmd.Parameters.AddWithValue("#Mobile_No", this.Textbox4.Text);
cmd.Parameters.AddWithValue("#Office_Address", this.Textbox5.Text);
cmd.Parameters.AddWithValue("#House_Address", this.Textbox6.Text);
cmd.Parameters.AddWithValue("#CNIC", this.Textbox7.Text);
cmd.Parameters.AddWithValue("#Item_name", this.Textbox14.Text);
cmd.Parameters.AddWithValue("#Item_color", this.Textbox15.Text);
cmd.Parameters.AddWithValue("#Item_model", this.Textbox16.Text);
cmd.Parameters.AddWithValue("#Item_engine_NO", this.Textbox17.Text);
cmd.Parameters.AddWithValue("#Item_chasis_NO", this.Textbox18.Text);
cmd.Parameters.AddWithValue("#Cash_price", this.Textbox19.Text);
cmd.Parameters.AddWithValue("#Installment_price", this.Textbox20.Text);
cmd.Parameters.AddWithValue("#Advance_given", this.Textbox21.Text);
cmd.Parameters.AddWithValue("#Amount_left", this.Textbox25.Text);
cmd.Parameters.AddWithValue("#Monthly_Installment", this.Textbox22.Text);
cmd.Parameters.AddWithValue("#Monthly_Rent", this.Textbox23.Text);
cmd.Parameters.AddWithValue("#Date_of_giving", this.Textbox24.Text);
cmd.Parameters.AddWithValue("#Sponsor_name", this.Textbox8.Text);
cmd.Parameters.AddWithValue("#Sponsor_father_name", this.Textbox9.Text);
cmd.Parameters.AddWithValue("#Sponsor_profession", this.Textbox10.Text);
cmd.Parameters.AddWithValue("#Sponsor_Address", this.Textbox11.Text);
cmd.Parameters.AddWithValue("#Sponsor_CNIC", this.Textbox12.Text);
cmd.Parameters.AddWithValue("#Sponsor_Mobile_No", this.Textbox13.Text);
try
{
cmd.ExecuteNonQuery();
MessageBox.Show("Successfully saved");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
To edit, insert, in general interact with your database you need the class SqlCommand. First you create a connection to your database with an SqlConnection object. Then you pass the SQL statement as a string and the connection into the constructor of the SqlConnection class. Little example:
SqlConnection con = new SqlConnection("server=localhost;database=test_db;uid=root;password=yourpassword");
SqlCommand cmd = new SqlCommand("select * from your_table", con);
To retreive the data from the database you need to use the SQL Statements. For example an SQL statement is something like:
insert into my_table (value1, value2)
values("Example", "Insertion");
When you created your SqlConnection and the SqlCommand you need to open the database connection and execute the command. Wether it's a command for receiving information from the database or editing the database you use ExecuteReader() or ExecuteNonQuery(). For example when you want to receive all the Information stored in one table you use:
SqlConnection con = new SqlConnection("connection string as shown above");
SqlCommand cmd = new SqlCommand("select * from example_table", con);
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
while(reader.Read())
Console.WriteLine(reader[<table_index or attribute Name>]);
And finally dont forget to call the close method on your SqlConnection and SqlDataReader object
You are probably making two mistakes:
Problem 1. Your connecting string looks like wrong. Instead of:
Data Source=(localdb)shop_database;Initial Catalog=shop_database;Integrated Security=True";
It should be:
Data Source=(LocalDb)\MSSQLLocalDB;Initial Catalog=shop_database;Integrated Security=True";
Problem 2. You are not opening the connection before executing the command. Your code in the block should be like this:
try
{
conn.Open(); // Open the connection
cmd.ExecuteNonQuery();
MessageBox.Show("Successfully saved");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
conn.Close(); // Close the connection
}
As a best practice, I recommend that you use "using" block to create your connection. In that case, you don't have to explicitly close the connection and set it to null:
try
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
conn.Open();
// Remaining code
}
}
catch(Exception ex)
{
// Manage your exception here
}

Execute any Raw SQL Query

IS it possible to execute a raw SQL command of any type (SELECT, UPDATE, DELETE....) in C#. I am looking to add a feature similar to the SQL Server Management Studio query window where I can just type in any SQL command and it executes it. In my case I am not worried about sql injection, I know this risk with this feature. All the connection parameters are passed to me (I have a valid connection string), but I know nothing about the database itself. The SQL command is also syntactically correct before I get the command. I cannot seem to find a solution that will work in all cases, probably just overlooking the obvious solution.
Here is an ADO example for you
using System;
using System.Data;
using System.Data.SqlClient;
class Program
{
static void Main()
{
string connectionString =
"Data Source=(local);Initial Catalog=Northwind;"
+ "Integrated Security=true";
// Provide the query string with a parameter placeholder.
string queryString =
"UPDATE [dbo].[USR_Users] SET [Active] = 1 WHERE Id = 1";
using (SqlConnection connection =
new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(queryString, connection);
try
{
connection.Open();
command.ExecuteNonQuery();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadLine();
}
}
You can simply use ADO .NET and show the results of the query if it executed successfully or not, just put the following code in the event handler when you want to execute your query:
using (SqlConnection conn = ConnectionClass.GetInstance().Connection())
using (SqlCommand cmd = new SqlCommand(TextBoxQuery.Text, conn))
{
conn.Open();
TextBoxNoOfRowEffected.Text = cmd.ExecuteNonQuery().ToString();
}
SqlCommand.ExecuteNonQuery() Documentation

C# :error There is already an open DataReader associated with this Command which must be closed first

I used to call several functions with this connection string:
class Solders_DB
{
SqlConnection connection;
SqlCommand query;
String command;
public Solders_DB()
{
connection = new SqlConnection();
connection.ConnectionString = "Server=localhost;Database=Scheduling_Employee ;Trusted_Connection=True;MultipleActiveResultSets=True;";
query = new SqlCommand();
}
As you see I used this MultipleActiveResultSets=True; in my connection but in this function :
command = #"SELECT [GID] FROM [Scheduling_Employee].[dbo].[Solder] where [ID]=#ID";
query.CommandText = command;
query.Parameters.Clear();
query.Parameters.AddWithValue("#ID", id);
Object o= query.ExecuteScalar();
I faced with this error:
There is already an open datareader associated with this command which must be closed first
The code in your question is not complete. Please explain yourself better for further assistance.
When using a SqlConnection is recommended to use the 'using' statement like this:
using (SqlConnection SqlConn = new SqlConnection(ConnString))
{
try
{
SqlConn.Open();
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
return null;
}
}
You're trying to read data from the first execution of your query, please update your question and put the complete code and the error stack.
Its usually when there was another query before that one and has not yet stopped executing inside the database engine (maybe it was a heavy script). You could try query = new SqlCommand();, query.Cancel() or
while(query.Connection.State != System.Data.ConnectionState.Open){ Threading.Sleep(100);}

SqlConnection property in a custom asp.net database component

Im making a few static classes to avoid rewriting the same code multiple times and to keep all the database related methods in the same place.
the class look like this:
public static class Database_dbSurvey
{
public static DataSet GetQuestionari()
{
SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["default_connection"].ConnectionString);
string query = "[admin].[SRV_Categorie_Lista]";
SqlCommand cmd = new SqlCommand(query, connection);
cmd.CommandType = CommandType.StoredProcedure;
//GetDataSet use the SqlDataAdapter.fill() method
return Utils.GetDataSet(cmd);
}
etc.... (others similar methods)
}
I want to reduce the code and I want to make it more "object oriented", so I started by making a property for the SqlConnection (which is the same for every methods of this class).
private static SqlConnection connection
{
get { return new SqlConnection(ConfigurationManager.ConnectionStrings["default_connection"].ConnectionString); }
}
The problem is that it works perfectly with SqlDataAdapter.fill(), till I use a method like this:
using (connection)
{
connection.Open();
cmd.ExecuteNonQuery();
}
Now, the next usage of the connection will throw the "not istanziated" exception and I can't understand why.
what is the correct way to define the connection property?
p.s.
if you have other suggestion on improving the code it will be higly appreciated
EDIT:
I still dont get it why the "new" keyword do not create another istance of the SQLConnection everytime I call it.
however I made some changes to make the code safer:
private static string connection_string
{
get { return ConfigurationManager.ConnectionStrings["Connection_dbPrysmianSurvey"].ConnectionString; }
}
public static DataSet GetQuestionari(string username)
{
string query = "[dbo].[SRV_Test_Lista]";
using (SqlConnection connection = new SqlConnection(connection_string))
using (SqlCommand cmd = new SqlCommand(query, connection))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#username", username);
return Utils.GetDataSet(cmd);
}
}
public static int CreaTest(string ID_questionario, string username)
{
string query = "[dbo].[srv_test_genera]";
using (SqlConnection connection = new SqlConnection(connection_string))
using (SqlCommand cmd = new SqlCommand(query, connection))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#ID_categoria", ID_questionario);
cmd.Parameters.AddWithValue("#ID_utente", username);
connection.Open();
return (int)cmd.ExecuteScalar();
}
}
But considering the fact that I have 40-50 methods it's still is a pain to rewrite the same lines 40-50 times, any suggestions?
Do not use using keyword in your case.
It will dispose the connection after that using's scope is complete by calling SqlConnection.Dispose method.
using(connection) {...}'s equivalent -
try
{
connection.Open();
cmd.ExecuteNonQuery();
}
catch
{
throw;
}
finally
{
connection.Dispose();
}
As #Parag Meshram mentioned, using keyword disposes everything inside itself when completed.
There are two ways I can suggest:
(1) Don't make connection a static method
private SqlConnection connection() { get { return new
SqlConnection(ConfigurationManager.ConnectionStrings["default_connection"].ConnectionString);}
}
then use it like
SqlConnection newConnection = connection();
using (newConnection) { ... }
Or
(2) Keep your static method as is but use it like this:
try {
connection.Open();
cmd.ExecuteNonQuery(); } catch {
throw; }
This way, your connection is not disposed.
I had the same problem a year ago and that's now I resolved it, using method (2).

Simple sql query not working

I tried to insert some data into my database (sql server/local file) but it doesn't work.
public bool SaveCookie(string cookie, string expires)
{
SimpleDBM db = new SimpleDBM();
db.Connect();
try
{
string query = string.Format("INSERT INTO Cookies(cookie_value, cookie_expires) VALUES('{0}', '{1}');", cookie, expires);
SqlCommand cmd = new SqlCommand();
cmd.CommandText = query;
//...
SqlDataReader data = db.Query(ref cmd);
return data.Read();
}
catch
{
return false;
}
finally
{
db.Close();
}
}
The SimpleDBM class:
public class SimpleDBM {
public static string dbpath = #"...";
public static string dbname = "db.mdf";
public static string dfullPath = Path.Combine(dbpath, dbname);
public static string connStr = string.Format(#"Data Source=.\SQLEXPRESS;AttachDbFilename={0};Integrated Security=True;Connect Timeout=30;User Instance=True", dfullPath);
private SqlConnection con;
public void Connect()
{
con = new SqlConnection();
con.ConnectionString = connStr;
con.Open();
}
public SqlDataReader Query(ref SqlCommand cmd)
{
cmd.Connection = con;
return cmd.ExecuteReader();
}
public void Close()
{
con.Close();
}
}
Can someone point out my mistake? For other queries it seems to work fine.
Thanks in advance.
The problem seems to be that you're trying to execute a query that doesn't return a result set using the ExecuteReader method of the SqlCommand class which will attempt to execute your query and create and return a DataReader for an eventual result set.
You should use ExecuteNonQuery for INSERT and UPDATE sql statements.
SIDE NOTE
Not that it's the reason you're getting the error but you should also consider using SqlParamters instead of composing the values into the INSERT statement. Using prepared SQL statements generally gives a performance enhancement and also helps prevent SQL injection attacks.
For an example of using prepared statements, see the MSDN page or the Prepare method.
You are using a ExecuteReader when you should be using ExecuteNonQuery.
Not related to your error you really should not be using String.Format with SqlCommand. What you should do is
string query = "INSERT INTO Cookies(cookie_value, cookie_expires) VALUES(#cookie, #expires);", cookie, expires);
SqlCommand cmd = new SqlCommand();
cmd.Parameters.AddWithValue("#cookie", cookie);
cmd.Parameters.AddWithValue("#expires", expires);
cmd.CommandText = query;
With your method ask your self if someone passed a cookie of ' ''); Drop table Cookies --? This is called a "Sql Injection Attack" and is one of the top 5 reasons websites get hacked.
EDIT
Just to help give another example of why using String.Format to pass values you did not generate is bad.

Categories

Resources