Cannot execute mysql store procedure with out parameter in asp.net - asp.net

I have this store procedure with out parameter
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `usp_count_rows`(OUT total int)
BEGIN
SELECT COUNT(*)
FROM address_book.persons;
END
I want to use it in asp.net page. I write this code behind:
string commandText = "usp_count_rows";
MySqlConnection conn = new MySqlConnection(ConfigurationManager.ConnectionStrings["mySqlString"].ConnectionString);
MySqlCommand cmd = null;
try
{
cmd = new MySqlCommand(commandText, conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("total", MySqlDbType.Int32);
cmd.Parameters["total"].Direction = ParameterDirection.Output;
conn.Open();
cmd.ExecuteNonQuery();
int total = (int)cmd.Parameters["?total"].Value;
}
catch (MySqlException ex)
{
MessageBox.Show(ex.Message);
}
finally
{
conn.Clone();
}
and i got this error message
Specified cast is not valid.
fot the line
int total = (int)cmd.Parameters["?total"].Value;
What should I do to make the code work. And another thing I want ot use the result in aspx page. Something like this: Total number of rows: (result from store procedure). Do you have some suggestions?

This is happening because your SP doesn't return any parameters, just result of the query. And for a stored procedure like this you do not need any parameters - even output ones, so redefine your SP simple as
CREATE DEFINER=`root`#`localhost` PROCEDURE `usp_count_rows`
BEGIN
SELECT COUNT(*)
FROM address_book.persons;
END
Then in you C# get rid of lines (remove them completely):
cmd.Parameters.Add("total", MySqlDbType.Int32);
cmd.Parameters["total"].Direction = ParameterDirection.Output;
and replace these lines:
cmd.ExecuteNonQuery();
int total = (int)cmd.Parameters["?total"].Value;
with this one line:
int total = Convert.ToInt32(cmd.ExecuteScalar());
ExecuteScalar method executes your SP/Query and returns first column of first row of that query (in your case it will be the only column and the only row with the Count(*)).
Oh by the way in your Finally block it should be conn.Close() not conn.Clone(), but I think it's simple a type.
As for displaying results on the ASPX page - there're multiple ways depending on where and how you want to display it. For example you can add a Label control to your page and execute something like:
Label1.Text = "Total number of rows: " + total.ToString();

Related

Counter variable not working Asp.net webform

I have a method to check if the id exists in a table and if it does insert into another database table; additionally I have label that will display the number of data entered. The query to insert into the database and select from the database works fine; but my problem is I'm not able to count, only receiving a count of 1 at all times. It is not incrementing; my question how do I get the counter to increment rather than just showing 1 at all times. This is what I have so far
protected void btnComplete_Click(object sender, EventArgs e)
{
string id = txtid.Text;
string user = lblUsername.Text;
string date = lblDate.Text;
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["TWCL_OPERATIONSConnectionString"].ToString());
//commands identifying the stored procedure
SqlCommand cmd = new SqlCommand("selectId", conn);
SqlCommand cmd1 = new SqlCommand("CreateUserId", con);
// execute the stored procedures
cmd.CommandType = CommandType.StoredProcedure;
cmd1.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#id", id);
conn.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
cmd1.Parameters.Add("#id", SqlDbType.NVarChar).Value = barcode);
cmd1.Parameters.Add("#Username", SqlDbType.NVarChar).Value = user;
cmd1.Parameters.Add("#Date", SqlDbType.DateTime).Value = date;
counter = counter + 1;
}
reader.Close();
cmd1.ExecuteNonQuery();
lblCount.Text = counter.ToString();
}
else
{
lblError.Text = barcode + " does not exist!!";
}
}
Before you are asked for stored procedures and before giving you a concrete answer, you should fix some problems in your code
1) use using{} blocks with command and connection to make sure they are disposed.
2) In while loop, you are adding parameters to cmd1. Think what will happen if while loop runs more than 1 time!!
Now, if you want to show max in counter, just get max from database !!
In your cmd object you are sending some ID to stored procedure. It will always return 1 record if id is unique in your table.
So your counter is always 1
Solution
Not modifying much of your code, add count(id) as counter in your storedprocedure query returning result of cmd.
And in the while loop assign that to counter variable.
counter = Convert.ToInteger(reader[“counter”].ToString());
Above is not best solution though. As it will count records for all rows and will reduce performance over time.
For best solution, you need to make another command object that executes a query like select count(id) from YourTableName
This will give you number of records in your table.
Edit
From your comment.
You only want total records after inserting from cmd1.
Just do following:
1) In your storedProcedure for cmd 1, write Select Isnull(count(*),0) from YourTableNameHere
2) In your code, use ExecuteScalar instead of ExecuteNonQuery.
var result = cmd1.ExecuteScalar();
lblCount.Text = result.ToString();
Edit 2
You want to keep track of number of records inserted in current session. Use viewstate or session, depending on your requirement to save counter for session Or only untill user stays on current page.
var recordsAdded = cmd1.ExecuteNonQuery();
if(Session[“counter”] == null)
{
Session[“counter”] = 0;
}
if(recordsAdded>0)
{
Session[“counter”] = Convert.ToInteger(Session[“counter”]) + 1;
}
lblCount.Text = Session[“counter”];
Above will keep track of inserted records in session

Binding Checklistbox with SqlServerDatabase

I want to Bind a checklistbox with Database in sqlserver2008. I am working in asp.net C# on a user control Module. I wrote a code. i want to know whether the code is perfact or not and also want to know that in which event i should place this code to get proper output.
{
int Post_Id = int.Parse(ViewState["ID"].ToString());
SqlConnection cn1 = new SqlConnection();
cn1.ConnectionString=
ConfigurationManager.ConnectionStrings["SiteSqlServer"].ConnectionString;
SqlDataAdapter da = new SqlDataAdapter("SelectTags", cn1);
DataTable ds = new DataTable();
SqlCommand cmnd1 = new SqlCommand("SelectTags", cn1);
cmnd1.Parameters.AddWithValue("#Post_Id",Post_Id);
cmnd1.CommandType = CommandType.StoredProcedure;
cn1.Open();
cmnd1.ExecuteNonQuery();
da.Fill(ds);
cn1.Close();
foreach (DataRow dr in ds.Rows)
{
String field1 = dr["Tag_Name"].ToString();
CheckBoxList2.Items.Add(field1);
CheckBoxList2.DataBind();
}
}
SQL query for sql server 2008
GO
/****** Object: StoredProcedure [dbo].[InsertPost2Tag] Script Date: 04/02/2013 09:47:01 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
Alter PROCEDURE [dbo].[SelectTags]
-- Add the parameters for the stored procedure here
#Post_Id int
AS
BEGIN
SELECT mst_Tag.Tag_Name FROM mst_Tag INNER JOIN Post2Tag ON mst_Tag.tagId = Post2Tag.Tag_Id Where Post2Tag.Post_Id=#Post_Id
END
GO
Do this in page load witin
if(!ispostback){
CheckBoxList2.DataSource = ds; //This is the dataset that you fill from your stored procedure;
CheckBoxList2.DataTextField = "Tag_Name";
CheckBoxList2.DataValueField = "Tag_Name_Id";
CheckBoxList2.DataBind();
}
and take one more parameter Tag_Name_Id in your sp query..
SELECT mst_Tag.Tag_Name,Tag_Name_Id FROM mst_Tag INNER JOIN Post2Tag ON mst_Tag.tagId = Post2Tag.Tag_Id Where Post2Tag.Post_Id=#Post_Id
Remove this from your code
foreach (DataRow dr in ds.Rows)
{
String field1 = dr["Tag_Name"].ToString();
CheckBoxList2.Items.Add(field1);
CheckBoxList2.DataBind();
}
Hope this helps... If it is what you were asking for?
No need to do any thing Just choose data source for check list box and set the session variable with selected value of grid view in its selected index changed event.
It worked for me... and too easy to implement.

oraclehelper filldataset or another way to get SYS_REFCURSOR values at ASP.NET

To whom it may respond to,
We are developing our project using .net framework 4.0,Oracle 11gR2. The problem is that , we have to use Oraclehelper class, no other options, and we can't get SYS_REFCURSOR values . When googled ,
we have catched some pages writing about filldataset method of oraclehelper class, but this class doesn't exist in our Oraclehelper class.
Any workarounds, templates, examples etc. to get SYS_REFCURSOR values via Oraclehelper class?
Thank you for your concern,
Best Regards,
Kayhan YÜKSEL
assuming you are using the sourceforge.net/projects/oraclehelpernet "oraclehelper" it is build ontop of ODP (ie Oracle.DataAccess.Client)
all you would need to do is:
(this is from http://download.oracle.com/docs/cd/B28359_01/win.111/b28375/featRefCursor.htm)
String cmdTxt1 = "begin open :1 for select col1 from test; end;";
OracleCommand cmd = new OracleCommand(cmdTxt1, conn);
OracleParameter outRefPrm = cmd.Parameters.Add("outRefPrm",
OracleDbType.RefCursor, DBNull.Value, ParameterDirection.Output);
cmd.ExecuteNonQuery(); // Execute the anonymous PL/SQL block
You can also look in %oracle_home%\client_1\odp.net\samples\4\RefCursor for 7 examples (this is when ODP is installed that is)
Since the OracleHelper just creates a wrapper around ODP, all you need to do is create the parameter as OracleDbType.RefCursor and pass it into the call (be it an execute non-query or datareader or whatnot)
now to do this via a procedure:
PROCEDURE Get1CurOut(p_cursor1 out refCursor) is
BEGIN
OPEN p_cursor1 for select * from emp;
END Get1CurOut;
and to the C#
OracleCommand cmd = new OracleCommand("Get1CurOut", con);
cmd.CommandType = CommandType.StoredProcedure;
// Bind
OracleParameter oparam = cmd.Parameters.Add("refcursor", OracleDbType.RefCursor);
oparam.Direction = ParameterDirection.Output;
try
{
// Execute command; Have the parameters populated
cmd.ExecuteNonQuery();
// Create the OracleDataAdapter
OracleDataAdapter da = new OracleDataAdapter(cmd);
// Populate a DataSet with refcursor1.
DataSet ds = new DataSet();
da.Fill(ds, "refcursor1", (OracleRefCursor)(cmd.Parameters["refcursor1"].Value));
// Print out the field count the REF Cursor
Console.WriteLine("Field count: " + ds.Tables["refcursor1"].Columns.Count);
}
this is lifted (with slight modification) from %oracle_home%\client_1\odp.net\samples\4\RefCursor\sample1.cs
here is an (untested) OracleHelper example:
string connectionString = "User Id=scott;Password=tiger;Data Source=oracle";
CommandType commandType = CommandType.StoredProcedure;
string commandText = "Get1CurOut";
OracleParameter oparam = cmd.Parameters.Add("refcursor", OracleDbType.RefCursor);
oparam.Direction = ParameterDirection.Output;
OracleDataReader reader;
reader = OracleHelper.ExecuteReader(connectionString, commandType, commandText, oparam) ;
// show the first row
reader.Read();
// Print out SCOTT.EMP EMPNO column
Console.WriteLine("EMPNO: {0}", reader.GetDecimal(0));
// Print out SCOTT.EMP ENAME column
Console.WriteLine("ENAME: {0}", reader.GetString(1));

SQLDataReader find value of each row

I used to use datasets instead of sqldatareaders and I used to be able to do something like this
If dataset.tables(0).Rows(0)(1).ToString()) = "N" Then
lbl.Text = dataset.tables(0).Rows(0)(2).ToString())
Else
'Do Nothing
End If
This obviously doesn't work with sqldatareaders.
I have code to see if the SQLDatareader has any rows but was wondering if there was a way to get the value of each row
I'm guessing this is possible and i've had a look around but can't seem to find anything
Dim conn As SqlConnection = New SqlConnection("server='h'; user id='w'; password='w'; database='w'; pooling='false'")
conn.Open()
Dim query As New SqlCommand("DECLARE #investor varchar(10), #sql varchar(1000) Select #investor = 69836 select #sql = 'SELECT * FROM OPENQUERY(db,''SELECT * FROM table WHERE investor = ''''' + #investor + ''''''')' EXEC(#sql)", conn)
Dim oDR As SqlDataReader = query.ExecuteReader()
If oDR.HasRows or dataset.tables(0).Rows(0)(1).ToString()) = "N" Then
lbl.Text = dataset.tables(0).Rows(0)(2).ToString())
Else
'Do Nothing
End If
That is the code I have at the moment which obviously doesn't work
Any ideas?
Thanks
When you use the data reader you have to step through each row yourself. Using HasRows is a good start, for it will tell you if the returned result set is empty.
To iterate through the result set you should use the Read() method. It will return true if you are at a row and false when you have moved past the last row.
My Vb is poor so I will give you an example in C# instead:
if (oDR.HasRows && oDR.Read())
{
if (oDR.GetString(0) == "N")
{
lbl.Text = oDr.GetString(1);
}
}
Here I first check that we have a result set with data and then try to move to the first row. If this succeeds I then read the string value of the first column and compare it to "N". If the value is equal to "N" I set the Text property of the lbl variable to the string value of the second column.
This should be equivalent to your algorithm with the dataset. I recommend that you read the MSDN documentation for the SqlDataReader. It is quite good and the example code is useful.

SqlDataReader Column Ordinals

Suppose I am calling a query "SELECT name, city, country FROM People". Once I execute my SqlDataReader do columns come in the same order as in my sql query?
In other words can I rely that the following code will always work correctly:
SqlConnection connection = new SqlConnection(MyConnectionString);
SqlCommand command = new SqlCommand();
command.Connection = connection;
command.CommandText = "SELECT [name], [city], [country] WHERE [id] = #id";
try
{
connection.Open();
SqlDataReader reader = command.ExecuteReader(System.Data.CommandBehavior.SingleRow);
if (reader.Read())
{
// Read values.
name = reader[0].ToString();
city = reader[1].ToString();
country = reader[2].ToString();
}
}
catch (Exception)
{
throw;
}
finally
{
connection.Close();
}
Also how much performance do I lose if I use column names instead of ordinals (reader["name"])?
Are there any official microsoft documents describing the behavior of column ordering in SqlDataReader?
Yes they do but you can also use SqlDataReader.GetName(ordinal) and SqlDataReader.GetOrdinal(name).
As for performance, I think it's probably extremely insignificant compared to the overhead of say, retrieving the next row of data.
I totally agree with Josh - the positions of the fields are indeed such as you specify them in your SQL query text.
BUT: I would still prefer to use the column names, since it's more robust. E.g. what if you need to add a field to your SQL query?
command.CommandText = "SELECT [name], [jobtitle], [city], [country] WHERE [id] = #id";
Now suddenly you have to rewrite all your code to change the positions....
What I normally do outside the loop that enumerates through all the rows returned by the data reader is determine the positions of each field I'm interested in:
int namePosition = reader.GetOrdinal("name");
int cityPosition = reader.GetOrdinal("city");
and then I use these positions inside my loop handling the data to get quick access to the individual fields. That way you determine the positions only once, but you're using positions in your looping over the data - the best of both worlds! :-)
Marc
This example is the most maintainable and easiest to read:
int? quantity = reader.Get<int?>("Quantity");
Guid token = reader.Get<Guid>("Token");
It relies on the following extension method I created. It performs DB null checks, provides an informative error message when field is not found, and does not break when columns are re-aligned.
internal static T Get<T>(this SqlDataReader reader, string fieldName)
{
int ordinal;
try
{
ordinal = reader.GetOrdinal(fieldName);
}
catch (IndexOutOfRangeException)
{
throw new IndexOutOfRangeException(string.Format("Field name '{0}' not found.", fieldName));
}
return !reader.IsDBNull(ordinal) ? (T)reader.GetValue(ordinal) : default(T);
}

Resources