Program doesn't send parameters to stored procedure - c#

I wrote program which selects and should delete a row from gridview based on the ID but it throws an exception that #ComplainantTypeID is not provided to the stored procedure but I checked in debugging, it sends and adds value but it still throws exception.
Code:
protected void btnDeletePopUp_Click(object sender, EventArgs e)
{
try
{
int ComplainantTypeID = Convert.ToInt32(txtSelectedID.Text.Trim());
ManageComplainantType mngComplainantType = new ManageComplainantType();
mngComplainantType.Delete(ComplainantTypeID);
Clear(txtName, txtSelectedID);
HiddenFieldSetMessage.Value = "Delete";
HiddenFieldShowMessage.Value = "True";
}
catch (Exception)
{
HiddenFieldSetMessage.Value = "NotDeleted";
HiddenFieldShowMessage.Value = "True";
}
}
Delete function in BLL:
public void Delete(int ComplainantTypeID)
{
SqlCommand cmd = new SqlCommand("DeleteComplainantTypes_SP", DataBaseConnection.OpenConnection());
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter pComplainantTypeID = new SqlParameter("#ComplainantTypeID", ComplainantTypeID);
cmd.Parameters.Add(pComplainantTypeID);
cmd.ExecuteNonQuery();
DataBaseConnection.CloseConnection();
}
Stored procedure:
PROCEDURE [dbo].[DeleteComplainantTypes_SP]
#ComplainantTypeID smallint
AS
BEGIN
BEGIN TRY
DELETE FROM ComplainantTypes WHERE ComplainantTypeID = #ComplainantTypeID
END TRY
BEGIN CATCH
SELECT ERROR_MESSAGE() AS ErrorMessage
END CATCH
END

Try
cmd.Parameters.AddWithValue("#ComplainantTypeID", value);
or
SqlParameter pComplainantTypeID = new SqlParameter("#ComplainantTypeID",SqlDbType.SmallInt,value);

You must show exception for better assistance, but the problem actually is in data type. You pass int but expected smallint. Look at the SQL Server Data Type Mappings article to choose appropriate data type.
UPDATE
You cant convert int to smallint you must pass parameter of type short which maps to smallint sql type.
Declare
public void Delete(short ComplainantTypeID)
instead of
public void Delete(int ComplainantTypeID)
and keep SP unchanged.

try this
sqlCommand.Parameters.Add("#ComplainantTypeID", SqlDbType.Int).Value = ComplainantTypeID;

Related

How can I receive SQL Messages in c#?

I want to show these SQL messages in c#
My C# code:
SqlCommand cmd = new SqlCommand();
cmd = con.CreateCommand();
string ab = "";
con.FireInfoMessageEventOnUserErrors = true;
con.InfoMessage += delegate(object obj, SqlInfoMessageEventArgs err)
{
ab = "\n " + err.Message;
message_richTextBox.Text += (ab);
};
cmd.CommandText = #"execute my_sp ";
cmd.ExecuteNonQuery();
con.FireInfoMessageEventOnUserErrors = false;
Problem:
My problem is that I don't get all SQL messgaes as in SQL Server 2008 (image attached) in C#
Some of those are not 'messages' (ie. TDS ERRROR and INFO Messages) but instead are rowcounts. SSMS displays them in the output in a similar manner to Info messages, but they're unrelated.
You get them in SqlClient as return values from DML queries. In other words, the int returned by ExecuteNonQuery:
For UPDATE, INSERT, and DELETE statements, the return value is the number of rows affected by the command.
The messages proper, like 'deleting previous signoff', you already know how to get them: SqlConnection.InfoMessage event, just as in your code.
Declare the local variables and assign the messages and affected rowcount to the variables and make select at last.
Use the SQLDataReader to get the messages in C#
DECLARE #sMessage1 AS VARCHAR(100)
DECLARE #sMessage2 AS VARCHAR(100)
DECLARE #sMessage3 AS VARCHAR(100)
DECLARE #sAffectedRows1 AS VARCHAR(100)
DECLARE #sAffectedRows2 AS VARCHAR(100)
DECLARE #sAffectedRows3 AS VARCHAR(100)
SET #sMessage1 = 'something1'
First UPDATE query
SET #sAffectedRows1 = ##ROWCOUNT
SET #sMessage2 = 'something2'
Second UPDATE query
SET #sAffectedRows2 = ##ROWCOUNT
SET #sMessage3 = 'something3'
Third UPDATE query
SET #sAffectedRows3 = ##ROWCOUNT
SELECT #sMessage1 AS Msg1, #sMessage2 AS Msg2, #sMessage3 AS Msg3,
#sAffectedRows1 AS Rows1, #sAffectedRows2 AS Rows2, #sAffectedRows3 AS Rows3
I think SQLConnection will not help you to get those message that you see in SQL Server Management Studio.
To get that message you have to do following thing. ( Main SMO)
Use SQL Server Management Object ( You will find SQL server management object msi on Microsoft Site)
After that include reference of those DLL and use following code.
public static void ExecuteScript(string scriptContent)
{
SqlConnection conn = new SqlConnection(dbConnectionString);
conn.Open();
Server sqlServer = new Server(new Microsoft.SqlServer.Management.Common.ServerConnection(conn));
sqlServer.ConnectionContext.InfoMessage += new SqlInfoMessageEventHandler(ConnectionContext_InfoMessage);
sqlServer.ConnectionContext.ServerMessage += new Microsoft.SqlServer.Management.Common.ServerMessageEventHandler(ConnectionContext_ServerMessage);
sqlServer.ConnectionContext.ExecuteNonQuery(scriptContent);
}
static void ConnectionContext_ServerMessage(object sender, Microsoft.SqlServer.Management.Common.ServerMessageEventArgs e)
{
Console.WriteLine("Method : ConnectionContext_ServerMessage" + System.Environment.NewLine + e.Error.Message + System.Environment.NewLine);
}
static void ConnectionContext_InfoMessage(object sender, SqlInfoMessageEventArgs e)
{
Console.WriteLine(System.Environment.NewLine + e.Message + System.Environment.NewLine);
}

C# and SQL: Selecting a row, a get a column data to a variable

So basically i have an SQL server. I have 4 columns. I will design this table here:
varchar varchar int varchar
account password gmlevel pics
test test 3 url
First, my method checks that the entered account and password is equal (login query).
Then i want to check that the 'test' account how high acces (gmlevel) has to this, then save it to a variable.
It's need to be two query. But the gmlevel record is a very important to my program, and it's not working at all.
Here is my connection:
private void gmset ()
{
if (loggedin == true) {
try
{
using (var con2 = new SqlConnection())
{
string user = login.felhasz;
string query2 = "SELECT * FROM accounts WHERE account=#acc";
con2.ConnectionString = "connection string";
con2.Open();
var cm2 = new SqlCommand(query2, con2);
cm2.Parameters.AddWithValue("#acc", user);
SqlDataReader dr2 = cm2.ExecuteReader();
while (dr2.HasRows)
{
MessageBox.Show("ASD");
}
}
}
catch (Exception exe)
{
MessageBox.Show(exe.Message);
}
}
else {
MessageBox.Show("Failed!");
}
This code doesn't hold anything that you can use for getting the GMLevel. I've tried many things, i've been looking for answer now a day ago, still nothing.
/Sorry for multiple questioning but i'm getting further and closer to solution
You can call Read() method to get the gmlevel.
Try This:
int GameLevel;
while (dr2.Read())
{
int.TryParse(dr2["gmlevel"].ToString(),out GameLevel);
MessageBox.Show("ASD");
}
EDIT: i suspect that control is not entering the while loop.
Try This: Replace/Comment your while loop with following if-else block and see the results
if(dr2.Read())
{
MessageBox.Show("Record Found");
}
else
{
MessageBox.Show("Record Not Found!!!");
}
while (dr2.HasRows)
{
Object[] output = new Object[dr2.FieldCount];
dr2.GetValues(output);
MessageBox.Show(output[2].ToString());
}

If insert fails for one record delete all previously inserted row, is is possible in a transaction?

I have method in my code like SaveListOfObjects which I execute inside foreach loop and then insert records to SQL Server.
It works great when there is no error in data I am inserting. But if error occured then only valid data is inserted in SQL.
I want to do following:
Insert all record only in case that whole data is valid, and if one error occurred in inserting.
Delete all previously saved data in SQL.
So, I already tried with TransactionScope and SqlTransaction classes and even with SQL TRANSACTION but only thing I could manage is insert valid data and non-valid data was omitted.
Now, as far as I search on web, I found that parallel transaction is not possible. Also, SQL has Isolation Level which prohibited parallel tasks.
Is there any possible way to accomplish insert in SQL like ALL or NOTHING?
UPDATE:
My code is as following:
public int Ramiz_SavePack(IPacking pack)
{
using (var conn = (SqlConnection)connector.GetConnection())
{
conn.Open();
SqlTransaction transaction;
var comm = (SqlCommand)connector.GetCommand("Ramiz_Pack_Save");
comm.CommandType = CommandType.StoredProcedure;
transaction = conn.BeginTransaction();
comm.Transaction = transaction;
int rowNum = 0;
try
{
if (!string.IsNullOrEmpty(pack.BrojKolete))
comm.Parameters.Add("#BrojKolete", SqlDbType.NVarChar).Value = pack.BrojKolete;
else
comm.Parameters.Add("#BrojKolete", SqlDbType.NVarChar).Value = DBNull.Value;
comm.Parameters.Add("#Bosanski", SqlDbType.NVarChar).Value = pack.Bosanski;
comm.Parameters.Add("#Kom", SqlDbType.Float).Value = pack.Kom;
comm.Parameters.Add("#Vrsta", SqlDbType.NVarChar).Value = pack.Vrsta;
comm.Parameters.Add("#Datum", SqlDbType.Date).Value = pack.Datum;
comm.Parameters.Add("#BrojKamiona", SqlDbType.Int).Value = pack.BrojKamiona;
rowNum = comm.ExecuteNonQuery();
transaction.Commit();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
try
{
conn.Close();
transaction.Rollback();
}
catch (Exception ex2)
{
Console.WriteLine(ex2.Message);
}
}
return rowNum;
}
}
and calling this method inside this:
var pack = new Pack();
for (int i = 1; i < lastRow; i++)
{
pack.Ramiz_SavePack(new Packing
{
BrojKolete = Convert.ToString(brojKoleteRange.Offset[i, 0].Value2),
Bosanski = Convert.ToString(nazivArtiklaRange.Offset[i, 0].Value2),
Kom = Convert.ToDouble(komRange.Offset[i, 0].Value2),
Vrsta = Convert.ToString(vrstaRange.Offset[i, 0].Value2),
BrojKamiona = int.Parse(ddlBrojKamiona.SelectedItem.Value),
Datum = Convert.ToDateTime(txtDate.Text)
});
pnlMessageSuccess.Visible = true;
}
It looks to me like you are looping and calling the save method for each object. This isn't a problem if the transaction exists around that loop, but it doesn't. You are rollback/committing each object separately
You need to either create a list of objects to save and send it into the save method, or create a transaction that wraps the loop e.g.:
var list = new List<Pack>();
foreach(<your loop>)
{
list.Add(new Pack(<some values>);
}
SavePacks(list);
void SavePacks(IList<Pack> items)
{
<create connection and transaction here and loop through inserting each item, rollback on error>
}
or
using(var tran = new SqlTransaction())
{
<Do save logic here for all items and rollback if something went wrong>
}
Your problem lies in the fact that you open and close the transaction for every object that you write in the database. Of course this means that when you hit a problem with your data, the previous correct one has already written to the database and committed. So it cannot be rolled back.
The solution is to open the connection and the transaction outside your data insert method and pass these object instances inside the method.
public int Ramiz_SavePack(IPacking pack, SqlConnection conn, SqlTransaction transaction)
{
var comm = (SqlCommand)connector.GetCommand("Ramiz_Pack_Save");
comm.Connection = conn;
comm.CommandType = CommandType.StoredProcedure;
comm.Transaction = transaction;
....
}
.....
try
{
using (var conn = (SqlConnection)connector.GetConnection())
{
conn.Open();
SqlTransaction transaction = conn.BeginTransaction();
var pack = new Pack();
for (int i = 1; i < lastRow; i++)
{
pack.Ramiz_SavePack(new Packing
{
BrojKolete = Convert.ToString(brojKoleteRange.Offset[i, 0].Value2),
Bosanski = Convert.ToString(nazivArtiklaRange.Offset[i, 0].Value2),
Kom = Convert.ToDouble(komRange.Offset[i, 0].Value2),
Vrsta = Convert.ToString(vrstaRange.Offset[i, 0].Value2),
BrojKamiona = int.Parse(ddlBrojKamiona.SelectedItem.Value),
Datum = Convert.ToDateTime(txtDate.Text)
}, conn, transaction);
}
pnlMessageSuccess.Visible = true;
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
transaction.Rollback();
}
In this way the method that inserts data, when it fails, will raise an exception trapped by the calling code that has opened the connection and the transaction. This calling code could then call the rollback method to undo every object inserted so far.
It is easier to make constraints on the data entry objects like constraining a certain Textbox to accept only numbers or whatever you would like .
And as another idea .. try checking the data Accuracy before Querying it to the database
One way is to create a DataTable from your list by mapping each object in the list to a row of the DataTable. Then you can loop through the DataTable rows to perform the insert operation, and include this code block inside a Transaction. This will allow you to prevent entering partial data.
You may refer to this link to get an idea how to do the list to DataTable conversion.

Stored procedure called from C# doesn't update record

I have written a simple stored procedure for updating a record which isn't working but I can't work out why. No exceptions are thrown but the record doesn't update either.
See code below:
public int IMGId;
protected void btnUpdate_Click(object sender, EventArgs e)
{
string result = "";
string sSQL = "usp_imageloader_update";
using (SqlConnection dbConnection = new SqlConnection(CKS_app_settings.sql_conn_string_db))
{
// SqlTransaction tn=null;
try
{
dbConnection.Open();
//start Transaction
// tn = dbConnection.BeginTransaction();
SqlCommand command = new SqlCommand(sSQL, dbConnection);
//command.Transaction = tn;
command.CommandText = sSQL;
command.CommandType = CommandType.StoredProcedure;
command.CommandTimeout = 1024;
command.Parameters.AddWithValue("#p_image_id", IMGId);
command.Parameters.AddWithValue("#p_url", txtUrl.Text);
command.Parameters.AddWithValue("#p_alt_text", txtAlt.Text);
//command.Parameters.AddWithValue("#p_filepath", File1.Value);
//command.Parameters.AddWithValue("#p_cntr_id", str_id);
int rowsAffected = command.ExecuteNonQuery();
}
catch (SqlException ex)
{
// throw ex;
//If it failed for whatever reason, rollback the //transaction
//tn.Rollback();
//No need to throw because we are at a top level call and //nothing is handling exceptions
result = ex.InnerException.Message;
}
}
Stored procedure in SQL SERVER
USE [smsdb_test_griffin2]
GO
/****** Object: StoredProcedure [dbo].[usp_imageloader_update] Script Date: 01/04/2012 09:05:41 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER procedure [dbo].[usp_imageloader_update]
#p_image_id INT,
#p_url VARCHAR(255),
#p_alt_text VARCHAR(255)
as
UPDATE Image_Library_UK
SET
Url=#p_url,
Alt_text=#p_alt_text
WHERE Image_id=#p_image_id
Having tried it in isolation, assuming that this works ( and there is nothing glaringly obvious wrong ), I would assume that one of your parameters is not being set correctly. It could be that the IMGid is not right - which would have this effect - or it coudl be that the the url and alttext have already be reset to their values by the load of the page.
Check the values at the point of calling. It may be you need to use !Page.IsPostBack to not reset these values on a postback. It may be that you need to access them using the request variable - it does depend on the rest of your code.

stored procedure not getting parameter

Hi I have a stored procedure and a connection to the database. I have other similar code on my website that works just fine but for the life of me I cannot get this to work. I want the username of the person logged in to be passed as a parameter. I can get it stored in a session variable.
I wasnt sure how to transfer it from the session variable to the parameter so I put it into a label and sent it that way. It shows that it is getting that far but everytime I just get the message 'nothing found'
I have checked the stored procedure and that seems fine to me. Below is the code and stored procedure! please help!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Security;
using System.Data.SqlClient;
using System.Configuration;
using System.Data;
public partial class RescueOnlyPages_EditRescueDetails : System.Web.UI.Page
{
protected void page_PreInit(object sender, EventArgs e)
{
MembershipUser user;
try
{
if (User.Identity.IsAuthenticated)
{
// Set theme in preInit event
user = Membership.GetUser(User.Identity.Name);
Session["user"] = user;
}
}
catch (Exception ex)
{
string msg = ex.Message;
//Log error here
// We have set theme in web.config to Neutral so if there is
// an error with setting themes, an incorrect theme wont be displayed to a customer
}
}
protected void Page_Load(object sender, EventArgs e)
{
userLabel.Text = Session["user"].ToString();
SqlDataReader myDataReader = default(SqlDataReader);
SqlConnection MyConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["RescueAnimalsIrelandConnectionString"].ConnectionString);
SqlCommand command = new SqlCommand("sp_EditRescueDetails", MyConnection);
if (!User.Identity.IsAuthenticated)
{
}
else
{
command.Parameters.AddWithValue("#user", userLabel.Text.Trim());
}
try
{
MyConnection.Open();
command.CommandType = CommandType.StoredProcedure;
myDataReader = command.ExecuteReader(CommandBehavior.CloseConnection);
myDataReader.Read();
GridViewED.DataSource = myDataReader;
GridViewED.DataBind();
if (GridViewED.Rows.Count >= 1)
{
GridViewED.Visible = true;
lblMsg.Visible = false;
}
else if (GridViewED.Rows.Count < 1)
{
GridViewED.Visible = false;
lblMsg.Text = "Your search criteria returned no results.";
lblMsg.Visible = true;
}
MyConnection.Close();
}
catch (SqlException SQLexc)
{
Response.Write("Read Failed : " + SQLexc.ToString());
}
}
}
stored procedure
ALTER PROC [dbo].[sp_EditRescueDetails]
(
#user nvarchar(50)
)
AS
BEGIN
SELECT [PostalAddress], [Telephone_No], [Website], [Email]
FROM [RescueDetails]
Where [UserName] = #user
End
EDIT *
If I change the stored procedure and delete the
' Where [UserName] = #user '
line it brings in every user detail without any problem so I think it maybe something with this line or the
command.Parameters.AddWithValue("#user", userLabel.Text.Trim());
line that is causing me the problems
Try setting
command.CommandType = CommandType.StoredProcedure;
before
MyConnection.Open();
Also don't call myDataReader.Read(); if you are going to set the myDataReader as the data source for gridview. That will make it skip a row and if result has only one row then the grid will display nothing.
When adding command parameters of text type (varchar, nvarchar) ADO.NET works best when you supply the length of the text value.
Try adding the parameter and then setting the length property and then assigning the value property, rather than using AddWithValue.

Categories

Resources