c# sql stored procedure isn't committing - c#

Whenever I run the following code I get the expected output
private int NewBorrower(string givenName, string surname)
{
int returnValue = 0;
using (conn)
{
conn.Open();
string sql = "AddBorrower";
cmd = new SqlCommand(sql, conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#givenName", SqlDbType.NVarChar).Value = givenName;
cmd.Parameters.Add("#surname", SqlDbType.NVarChar).Value = surname;
SqlParameter id = cmd.Parameters.Add("#id", SqlDbType.Int);
id.Direction = ParameterDirection.ReturnValue;
try
{
cmd.ExecuteNonQuery();
returnValue = (int)cmd.Parameters["#id"].Value;
}
catch (Exception e)
{
Console.WriteLine("Commit Exception Type: {0}", e.GetType());
Console.WriteLine(" Message: {0}", e.Message);
}
}
return returnValue;
}
When run from the front end I get the results I want, but when I check the database it doesn't show up in the table.
For good measure this is also the stored procedure being used
CREATE PROCEDURE [dbo].[AddBorrower]
#givenName nvarchar(50),
#surname nvarchar(50),
#id int = NULL OUTPUT
AS
INSERT INTO llBorrowers (givenName, surname)
VALUES (#givenName, #surname);
SET #id = SCOPE_IDENTITY();
RETURN #id
I've tried using transactions on both the c# and sql sides, and that didn't work at all.
I should also mention that it is a local database, but I'm not sure that should affect it.

When you use the DataDirectory substitution string in a WinForms application, its real value changes depending on your debug or release configuration.
In DEBUG your DataDirectory points to PROJECTFOLDER\BIN\DEBUG (or x86 variation if it is the case).
So it is extremely easy to get fooled by this. You create a connection in server explorer but this connection is ignored by your code that works on a different database.
You could create another connection in Server Explorer and name it DebugConnection, still keeping the original one for schema changes while you use the DebugConnection to check if your code executes as expected
As a side note, keep particular attention to the property Copy To the Output Directory property on the MDF file if it is listed between the project items. If you set it to Copy Always every time you start a debug session a fresh copy of your db will be copied from the project directory to the output directory effectively destroying the updates executed by your code. I recommend to set it to Copy Never and handle manually the database schema changes
A reference: Where is DataDirectory

You may try creating a SQLTransaction in C# part
Also, try changing your code like -
//Just create a SQL connection - cmd = new SqlCommand(conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "AddBorrower";

Related

Why is my math not working on my SQL Server database?

I am developing an asp.net web application and I am trying to add a user xp system to it. I have a SQL Server database connected to it and I am trying to make a function that will give 5 experience points to the user.
I queried to the user that is logged in, accessed the user_xp column, and I am trying to add +5 to the old session variable for xp, then send that back into the database to be stored. Here is my code, I am not sure what is wrong with it.
void generateXp()
{
try
{
SqlConnection con = new SqlConnection(strcon);
if (con.State == ConnectionState.Closed)
{
con.Open();
}
SqlCommand cmd = new SqlCommand("UPDATE member_master_tbl SET user_xp = #user_xp WHERE " +
"user_name = '" + Session["username"].ToString().Trim() + "'", con);
int xp = 5;
int current_xp = Convert.ToInt32(Session["user_xp"]);
int new_xp = xp + current_xp;
string new_xp2 = Convert.ToString(new_xp);
cmd.Parameters.AddWithValue("user_xp", new_xp2);
}
catch (Exception ex)
{
}
}
Try renaming the SQL parameter to #user_xp.
cmd.Parameters.AddWithValue("#user_xp", new_xp2);
I don't have an accessible database to test. Also, you need to add the command to execute the query at the end.
cmd.ExecuteNonQuery()
That being said, it's a good practice to learn to separate DB queries to stored procedures or functions.
As others noted, you simply forgot to do a execute non query to run the command that you setup.
However, you can write things this way. You don't mention or note what the data type the experience points column is - I assumed "int".
So, your code block can be written this way:
using (SqlCommand cmd = new SqlCommand("UPDATE member_master_tbl SET user_xp = #user_xp WHERE user_name = #user",
new SqlConnection(strcon)))
{
cmd.Parameters.Add("#user_xp", SqlDbType.Int).Value = 5 + Session("user_xp");
cmd.Parameters.Add("#user", SqlDbType.NVarChar).Value = Session("username");
cmd.Connection.Open();
cmd.ExecuteNonQuery();
}
note how the command object has a connection object (so we don't need a separate one).
And while several people here "lamented" the string concentration to build the sql and warned about sql injection?
Actually, the introduction of # parameters for both values cleans up the code. So you get nice parameters - nice type checking, and you don't have to remember to add/use/have things like quotes around teh string, but not for numbers.
And I let .net cast the number expression from session() - this also likely is ok.
Also the "using block" also correctly cleans up the command object and also the connection object - so the using block is a good idea here.

Cannot create new record to the database; no error message

I'm trying to add new record to trans_daily table, however, the code snippet below executed on button click doesn't work.
THE PROBLEMATIC CODE
private void button1_Click(object sender, EventArgs e)
{
try
{
SqlConnection connection = new SqlConnection(conString);
connection.Open();
string strcom = "INSERT INTO trans_daily (retail_id, cust_name, quantity, " +
"price, date, visibility, remarks_id) VALUES (#RetailID, #CustomerName, " +
"#Quantity, #Price, #Date, #Visibility, #RemarksID)";
SqlCommand cmd = new SqlCommand(strcom, connection);
cmd.Parameters.AddWithValue("#RetailID", ddRetailType.SelectedValue);
cmd.Parameters.AddWithValue("#CustomerName", tbCustomer.Text);
cmd.Parameters.AddWithValue("#Quantity", float.Parse(tbQuantity.Text));
cmd.Parameters.AddWithValue("#Price", float.Parse(tbPrice.Text));
cmd.Parameters.AddWithValue("#Date", DateTime.Now);
cmd.Parameters.AddWithValue("#Visibility", 1);
cmd.Parameters.AddWithValue("#RemarksID", 1);
cmd.ExecuteNonQuery();
}
catch (Exception err)
{
Console.WriteLine(err.Message);
}
}
The following are the data types:
retail_id (int)
cust_name (varchar50)
quantity (float)
price (float)
date (datetime)
visibility (int)
remarks_id (int)
It's also worth to point out that no exception is being thrown.
What could have gone wrong?
THE WORKING CODE
In a separate function, I was able to pull out data from retail table on form load and placed the pulled out data to a dropdown list.
private void formAddTransaction_Load(object sender, EventArgs e)
{
try
{
objConnect = new DatabaseConnection();
conString = Properties.Settings.Default.MVGasConnectionString;
objConnect.Sql = "SELECT * FROM retail";
objConnect.connection_string = conString;
ds = objConnect.GetConnection;
MaxRows = ds.Tables[0].Rows.Count;
FillRetailTypes(conString);
}
catch (Exception err)
{
MessageBox.Show(err.Message);
}
}
public void FillRetailTypes(string constring)
{
ddRetailType.DataSource = ds.Tables[0];
ddRetailType.ValueMember = "id";
ddRetailType.DisplayMember = "type";
}
Try this code and you may find your error:
try
{
using(SqlConnection connection = new SqlConnection(conString))
using(SqlCommand cmd = new SqlCommand())
{
connection.Open();
string strcom = "INSERT INTO trans_daily ([retail_id], [cust_name], [quantity], " +
"[price], [date], [visibility], [remarks_id]) VALUES (#RetailID, #CustomerName, " +
"#Quantity, #Price, #Date, #Visibility, #RemarksID)";
cmd.CommandText = strcom;
cmd.Connection = connection;
cmd.Parameters.AddWithValue("#RetailID", SqlDbType.Int);
cmd.Parameter["#RetailID"].Value = ddRetailType.SelectedValue;
cmd.Parameters.AddWithValue("#CustomerName", SqlDbType.VarChar);
cmd.Parameter["#CustomerName"].Value = tbCustomer.Text;
cmd.Parameters.AddWithValue("#Quantity", SqlDbType.Float);
cmd.Parameter["#Quantity"].Value = float.Parse(tbQuantity.Text);
cmd.Parameters.AddWithValue("#Price", SqlDbType.Float);
cmd.Paramter["#Price"].Value = float.Parse(tbPrice.Text);
cmd.Parameters.AddWithValue("#Date", SqlDbType.DateTime);
cmd.Parameter["#Date"].Value = DateTime.Now;
cmd.Parameters.AddWithValue("#Visibility", SqlDbType.Int);
cmd.Parameter["#Visibility"].Value = 1;
cmd.Parameters.AddWithValue("#RemarksID", SqlDbType.Int);
cmd.Parameter["#RemarksID"].Value = 1;
int affectedRows = cmd.ExecuteNonQuery();
Console.WriteLine("You have inserted {0} rows", affectedRows);
}
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
This code will...
... automatically open and close your database connection and command object
... log the amount of affected rows in the database to the console
... log exception messages to the console. You may add a breakpoint to this line if you want to see the whole exception (if one occures)
As explained in this blog, it seems like the problem is in the connection string.
Inside the project folder, 2 .mdf files were created: one is found at the root of the folder (let's call it mdf_1) and the other is inside the bin\Debug folder (let's call it mdf_2).
Now, taking a look inside the Visual Studio (VS) editor, there are 2 .mdf files shown: one under the Server Explorer, and another under the Solution Explorer. Not taking note of the location (from the properties section) of these .mdf files made me think these 2 .mdf files were the same. The thing is, the one under the Server Explorer is mdf_1 while mdf_2 is the one under the Solution Explorer.
VS has a behavior that copies mdf_1 and overwrites mdf_2 everytime the program is run (because by default, .mdf is set to Copy always mdf_1 to mdf_2). My connection string was pointing to the mdf_2 which explains why despite cmd.ExecuteNonQuery() command returns 1, my successfully inserted records are always erased because of the behavior VS has. And since it is mdf_1 that is under Server Explorer, I could not verify the changes in DB. Simply put, I was making changes in mdf_2 while trying to look for the changes in mdf_1.
So to avoid this, I modified my connection string by changing the relative path |DataDirectory| in the connection string to the absolute path of mdf_1 so that no matter how often VS overwrites mdf_2, the changes I make during runtime in mdf_1 aren't overwritten. This was, changes are also reflected in the Server Explorer (where I verify if changes were actually made).
tl;dr : I was updating the .mdf file under bin\Debug folder during runtime while physically looking for the updates in the .mdf file located in the root of the project.

Empty database table

I want to insert values in "Navn" row and "Varenr" row in the DB table, when I'm clicking on a button. I have following code:
private void button2_Click(object sender, EventArgs e)
{
using (SqlConnection cn = new SqlConnection(#"Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\Produkt.mdf;Integrated Security=True"))
{
try
{
SqlCommand cm = new SqlCommand();
cm.Connection = cn;
string col1 = textBox2.Text;
string col2 = textBox3.Text;
//generate sql statement
cm.CommandText = "INSERT INTO ProduktTable (Navn,Varenr) VALUES (#col1,#col2)";
//add some SqlParameters
SqlParameter sp_add_col1 = new SqlParameter();
sp_add_col1.ParameterName = "#col1";
//data type in sqlserver
sp_add_col1.SqlDbType = SqlDbType.NVarChar;
//if your data type is not number,this property must set
//sp_add_col1.Size = 20;
sp_add_col1.Value = textBox2.Text;
//add parameter into collections
cm.Parameters.Add(sp_add_col1);
//in your insert into statement, there are how many parameter, you must write the number of parameter
SqlParameter sp_add_col2 = new SqlParameter();
sp_add_col2.ParameterName = "#col2";
//data type in sqlserver
sp_add_col2.SqlDbType = SqlDbType.NVarChar;
//if your data type is not number,this property must set
//sp_add_col2.Size = 20;
sp_add_col2.Value = textBox2.Text;
//add parameter into collections
cm.Parameters.Add(sp_add_col2);
//open the DB to execute sql
cn.Open();
cm.ExecuteNonQuery();
cn.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error\n" + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
But unfortunately, my data table is still empty:
I have set a breakpoint on the ExecuteNonQuery function, and it is triggered, when pressing on the button:
My table definition:
Your connection string is causing this:
Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\Produkt.mdf;Integrated Security=True"
|DataDirectory| Your database that is being updated in this method is in your App Data Directory while the one you are trying to retrieve data from is in your project folder...
|DataDirectory| is a substitution string that indicates the path to the database. DataDirectory also makes it easy to share a project and also to deploy an application. For my PC my App Data Directory is:
C:\Users\MyUserName\AppData\...
If you browse to this location and then go to following folders
...\Local\Apps\2.0\Data
You will be able to find your particular application directory probably stored with your assembly name, or some hash when you go there you will find it the database there is being updated just fine. This connection string is best for deployment.
You can also try this:
If you notice that Server Explorer is detecting all the databases on my PC and you can notice that there are couple of MINDMUSCLE.MDF files but all are at different paths, this is because there is one file in DEBUG directory, one in my PROJECT directory, one in my APP DATA directory. The ones starting with the numbers are stored in my APP DATA directories... If you select your respective database file and then run the SELECT query against it, you will get your data.
I made a tutorial some time ago. May be it will help you:
Check the value that ExecuteNonQuery is returning. It should return an int with the number of records affected by the SQL statement.
If it comes back with a value other than 0, then you know a record is being inserted somewhere. Before you close the connection, run a SQL query against the table to select all of the records and see if they come back through the code.
SELECT * FROM ProduktTable
If you get some records, then you may want to double check the database you're looking at through the IDE and the one your inserting records into through the code. It could be possible that you've got two different databases and you're querying one while inserting into another one.
Those are the steps that I would go through to help narrow down the issue and sounds like something I've probably done before. I hope it helps!

How To create a stored procedure for SQL Server from C# code?

I am trying to create a stored procedure in SQL server from a C# winforms application.
This is the function I have so far.
public void CreateStoredProcedure(string SPname)
{
try
{
string query = "CREATE PROCEDURE " + SPname + " AS SELECT * FROM People WHERE Address='Mumbai'";
connection.Open();
var command = new SqlCommand();
command.CommandType = CommandType.Text;
command.CommandText = "EXEC " + query;
command.ExecuteNonQuery();
}
finally
{
connection.Close();
}
}
Am I doing this right? I get an error message every time I try to achieve this.
Hey thanks a lot guys!! Its working now..
This is the code that finally did it..
public void CreateStoredProcedure(string SPname)
{
try
{
string query = "CREATE PROCEDURE " + SPname + " AS SELECT * FROM People WHERE Address='Mumbai'";
connection.Open();
var command = new SqlCommand();
command.Connection = connection;
command.CommandText = query;
command.ExecuteNonQuery();
var adapter = new SqlDataAdapter(command);
adapter.Fill(dt);
dgv.DataSource = dt;
}
finally
{
connection.Close();
}
}
much appreciated! :)
You do not need EXEC when creating a stored procedure
and you need an active connection
You can try:
command.CommandType = CommandType.StoredProcedure;
Initialize connection property of your command:
command.Connection = connection;
Alternatively, you can create a Stored Procedure using Common Language Run-time integration in stead of doing it on the fly.
How to: Create and Run a SQL Server Stored Procedure by using Common Language Run-time Integration
Deploy CLR Stored Procedure to database
In your attempt above the code will only be able to run as a once off as it contains a CREATE command. It must then change to ALTER there after or you need to drop it every time and re-created. this would not be the best practice but just keep in mind.
You need to define a connection object and link it with the command object
CommandObject.Connection= ConnectionObject;
Also the CommandType.Text is by default.
You could also check if you connection is open using
if(ConnectionObject.State== ConncetionState.Closed)
{
ConnectionObject.Open();
}
If it is closed, you will need an active Open connection to pass a query.

Create database without wizard c#

Today i'm working on a project where I will create a relational database through source code and not through the built-in wizard.I have been looking for tutorials which explain to me the processes of doing this but seem to not be able to do so. Most have tutorials on how to use the build-in wizard and add content to tables, my main goal is to actually have a utility that users could use which includes a self-building database. if you have examples of this, I would greatly appreciate it or if you know of any good tutorials that will be helpful too
Thanks!
class Program
{
static string strcon = #"user id = sde ; password = passrd;
server =dfgserver;database =valrollclients";
static SqlCommand cmdinserted = new SqlCommand();
static SqlConnection con; //declaring a connection object
static void Main(string[] args)
{
cmdinserted.CommandText = "[dbo].[prcinsert_client]";
cmdinserted.CommandTimeout = 0;
cmdinserted.CommandType = CommandType.StoredProcedure;
cmdinserted.Connection = con;
cmdinserted.Parameters.Add("#client_name",
SqlDbType.VarChar, 12).Value = "me";
cmdinserted.Parameters.Add("#client_lastname",
SqlDbType.VarChar, 15).Value = "abutair";
cmdinserted.Parameters.Add("#client_age ",
SqlDbType.Int, 4).Value = 4;
try
{
con.Open(); //open connection
cmdinserted.ExecuteNonQuery(); //execute the stored procedure
con.Close();//close connection
}
catch (SqlException) //catch an error
{
throw; //throw it back to the calling method
}
This is the code you have to run on the server:
USE master;
GO
CREATE DATABASE Sales
ON
( NAME = Sales_dat,
FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL \DATA\saledat.mdf',
SIZE = 10,
MAXSIZE = 50,
FILEGROWTH = 5 )
LOG ON
( NAME = Sales_log,
FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\salelog.ldf',
SIZE = 5MB,
MAXSIZE = 25MB,
FILEGROWTH = 5MB ) ;
GO
You can add it into a SqlCommand. You will need an SqlConnection which I see you have.
Hope it helps.
It seems like this is being made way more complicated than it needs to be if you're planning to use SQL server.
Your application offers the user a way to enter a SQL server instance location and user with admin rights.
You then have a class with various methods which create your database, create your tables etc.
So you would do:
1) If not exists create database X.
2) IF not exists create tables A B C etc
3) alter the tables to setup the relations
4) If not exists create stored proc spA spB etc etc
and just build up the database that way.
Each step above would be a separate method which executes some inline SQL.
If you write the SQL to always check if the thing you're going to create exists it can be used to upgrade as well as create.

Categories