Error converting nvarchar to int in ExecuteNonQuery - asp.net

I am getting an error for the following program in asp.net.
I have checked sql and name is in nvarchar.
{
con.Open();
SqlCommand cmd = new SqlCommand("bookinsertion2", con);
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#idnumber",txtid.Text);
cmd.Parameters.AddWithValue("#name", txtname.Text);
cmd.Parameters.AddWithValue("#year", txtyear.Text);
cmd.Parameters.AddWithValue("#department", txtdepart.Text);
cmd.Parameters.AddWithValue("#bookname", ddlbookavail.SelectedItem.ToString());
cmd.ExecuteNonQuery();
con.Close();
Response.Redirect("~/LendingForm2.aspx");
}
This is the code of the stored procedure
create Procedure [dbo].[bookinsertion2]
#idnumber int,
#name nvarchar(20),
#year int,
#department nvarchar(30),
#bookname nvarchar(25)
as
Begin
insert into tbllendinginfo values(#idnumber,#name,#year,#department,#bookname)
insert into tbllendinginfo(Dateofbooktaken) values(GETDATE())
update tblbookinfo set BooksAvailable=BooksAvailable-(select COUNT(Id) from tbllendinginfo where BookName=#bookname) where Name=#bookname
end
The error is " Conversion failed when converting the nvarchar value 'Mike' to data type int. "

The error message is clear, one or more of the parameters expected by the stored procedure are not of type nvarchar. Probably the #year and #idnumber parameters are an integers. If that's true then you need to call
cmd.Parameters.AddWithValue("#idnumber",Convert.ToInt32(txtid.Text));
cmd.Parameters.AddWithValue("#year", Convert.ToInt32(txtyear.Text));
Said that, please try, if possible to avoid the call to AddWithValue, in particular in case where strings or date are involved. AddWithValue determines the type of the parameter from the input value and most of the time is correct, but there are situations where it decides for a wrong datatype and the errors are difficult to find. Moreover AddWithValue with strings is a performance hurdle.
A better explanation could be found in these two articles.
Can we stop using AddWithValue() already?
How Data Access Code Affects Database Performance
You could rewrite the code above using the Object Initializer Syntax
{
con.Open();
SqlCommand cmd = new SqlCommand("bookinsertion2", con);
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.Add(
new SqlParameter
{
ParameterName = "#idnumber",
SqlDbType = SqlDbType.Int,
Value = Convert.ToInt32(txtid.Text)
});
cmd.Parameters.Add(
new SqlParameter
{
ParameterName = "#name",
SqlDbType = SqlDbType.NVarChar,
Size = 50,
Value = txtname.Text
});
cmd.Parameters.Add(
new SqlParameter
{
ParameterName = "#year",
SqlDbType = SqlDbType.Int,
Value = Convert.ToInt32(txtyear.Text)
});
cmd.Parameters.Add(
new SqlParameter
{
ParameterName = "#department",
SqlDbType = SqlDbType.NVarChar,
Size = 50,
Value = txtdepart.Text
});
cmd.Parameters.Add(
new SqlParameter
{
ParameterName = "#bookname",
SqlDbType = SqlDbType.NVarChar,
Size = 50,
Value = ddlbookavail.SelectedItem.ToString()
});
cmd.ExecuteNonQuery();
con.Close();
Response.Redirect("~/LendingForm2.aspx");
}
EDIT
After your edit I think the problem is in this line of the stored procedure:
insert into tbllendinginfo values(#idnumber,#name,#year,#department,#bookname)
You haven't specified the columns' names but just the parameters. So the server inserts the parameter following the order of definition of the columns in the datatable.
Of course, if the second column in the table is not the column that should receive the #name parameter you could have serious problems.
You could fix the problem listing the name of the columns in the same order iun which you put the parameter inside the VALUES clause or changing the order of the parameters to follow the order of the column names.
For example (I don't know the column names so you should fix them)
insert into tbllendinginfo (idnumber, name, bookyear, department, bookname)
values(#idnumber,#name,#year,#department,#bookname)

Related

What is wrong with the following query?

I have a table containing name, surname and email. I want to retrieve them from the table and so i write:
if (LoginAs.SelectedValue == "Administrator")
{
string result;
string query = "Select * from AdminTable where ID='"+ idBox.Text +"'";
cmd1 = new SqlCommand(query, con);
result = Convert.ToString(cmd1.ExecuteScalar());
Response.Redirect("Admin.aspx");
//Admin user = new Admin(idBox.Text, "Active", mail, firstName, LastName, passwordBox.Text);
}
The problem is, it only returns the name field of the specified row even though i wrote "Select *". What is wrong here?
ExecuteScalar returns just the first column of the first row, and ignores the rest.
So you should use ExecuteReader method. An example from MSDN:
using (SqlConnection connection = new SqlConnection(
connectionString))
{
connection.Open();
SqlCommand command = new SqlCommand(queryString, connection);
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
Console.WriteLine(String.Format("{0}", reader[0]));
}
}
Note that the while (reader.Read()) checks whether your query returned (more) results and positions the cursor on the next record, that you can then read. This example prints the first column's value.
The using statement makes sure the connection is closed after use, whatever happens.
Also, don't build your query directly with input from the user (such as the value of a TextBox), use parameters instead to prevent SQL injection attacks.
You must try ExecuteReader() instead of using ExecuteScalar()
ExecuteScaler is used in situation where we have to read a single value.eg:
select count(*) from tablename.
while
ExecuteReader is used for any result set with multiple rows/columns
(e.g., SELECT * from TableName)
Sample code:
string myQuery="Select * from AdminTable where ID=#myid";
SqlCommand cmd=new SqlCommand(myQuery,conn);
cmd.Parameters.AddWithValue("#myid", value);
conn.Open();
SqlDataReader dreader;
dreader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
while (dreader.Read())
{
string Value1= dreader["COl1"].ToString();
string Value2= dreader["COl2"].ToString();
}
dreader.Close();
Always use parameterized Query
You may try cmd1.ExecuteReader() instead.

SQL Server User-Defined Table Type and .NET

I had a need to pass an integer array to a stored procedure from .NET and so I googled the topic and eventually ran across Arrays and Lists in SQL Server 2008, written by Erland Sommarskog and supposedly considered the standard manner in which one goes about this process.
I've tried two different manners to pass a user-defined table type to a stored procedure, but I'm getting exceptions with each one. Both of these manners are similar to what Erland Sommarskog uses in the link above.
Manner #1 - Use DataTable as SqlParameter
DataTable dt = new DataTable();
dt.Columns.Add("n", typeof(int));
// Just adding 3 test rows to the DataTable
DataRow dr = dt.NewRow();
dr["n"] = 1;
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["n"] = 2;
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["n"] = 3;
dt.Rows.Add(dr);
// Creation of the SqlParameter
SqlParameter p = new SqlParameter();
p.ParameterName = "#ids";
p.Direction = ParameterDirection.Input;
p.SqlDbType = SqlDbType.Structured;
p.TypeName = "lstInt_TblType";
p.Value = dt;
// Blows up here
DataSet ds = DAWrapper.GetDataSet(
Common.GetDB(),
"usp_Test",
new SqlParameter[] { p });
The exception that I get states:
The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. Parameter 1 ("#ids"): Data type 0x62 (sql_variant) has an invalid type for type-specific metadata.
Manner 2 - Use List as SqlParameter
List<SqlDataRecord> lstSDR = new List<SqlDataRecord>();
SqlMetaData[] tvp_definition = { new SqlMetaData("n", SqlDbType.Int) };
// Just adding 3 test rows
SqlDataRecord rec = new SqlDataRecord(tvp_definition);
rec.SetInt32(0, 50);
lstSDR.Add(rec);
rec = new SqlDataRecord(tvp_definition);
rec.SetInt32(0, 51);
lstSDR.Add(rec);
rec = new SqlDataRecord(tvp_definition);
rec.SetInt32(0, 52);
lstSDR.Add(rec);
// Creation of the SqlParameter
SqlParameter p = new SqlParameter();
p.ParameterName = "#ids";
p.Direction = ParameterDirection.Input;
p.SqlDbType = SqlDbType.Structured;
p.TypeName = "lstInt_TblType";
p.Value = lstSDR;
// Blows up here
DataSet ds = DAWrapper.GetDataSet(
Common.GetDB(),
"usp_Test",
new SqlParameter[] { p });
And the exception that I get for this ones states:
No mapping exists from object type System.Collections.Generic.List`1[[Microsoft.SqlServer.Server.SqlDataRecord, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] to a known managed provider native type.
Other Info
lstInt_TblType is the User-Defined Table Type in my SQL Server 2008. It does exist (I triple-checked this!). It has one column called "n", of type int, primary key and doesn't allow nulls. I copied exactly how Erland set his up.
I also verified that the stored procedure usp_Test works from SQL Server Manager Studio, so I'm fairly certain that the exceptions are not issuing from that direction. This is the t-sql that I used to verify that the stored procedure works:
DECLARE #ids lstInt_TblType
INSERT #ids(n) VALUES(1),(2),(3)
EXEC usp_Test ids
Any suggestions on where to go with this would be greatly appreciated. Thanks!
*EDIT: *
The stored procedure usp_Test:
ALTER PROCEDURE [dbo].[usp_Test]
(
#ids lstInt_TblType READONLY
)
AS
BEGIN
SET NOCOUNT ON;
select *
from dbo.dat_MetaData
where MetaDataTypeID in (select n from #ids)
END
GO
Found a different way to go about doing it. This way uses the System.Data.SqlClient libraries to create a connection to the database, specify the stored procedure name, and then pass a parameter in as a DataTable that serves as the SQL Server user-defined table type.
using (SqlConnection conn = new SqlConnection(connStr)) {
SqlCommand cmd = conn.CreateCommand();
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.CommandText = "dbo.usp_Test";
cmd.Parameters.AddWithValue("#ids", dt);
conn.Open();
using (SqlDataReader sqlReader = cmd.ExecuteReader()) {
DataTable retTbl = new DataTable();
retTbl.Load(sqlReader);
}
}
You can also find good examples of how to pass table-valued parameter data to a stored procedure in Microsoft's own Table-Valued Parameters reference.

System.Data.SqlClient.SqlException: Invalid column name

Trying to do a recordset, I just want one column of data, but this code is giving me an error.. I'm an ASP.NET newb, can anyone help?:
System.Data.SqlClient.SqlException: Invalid column name
'CustomerName'.
using (SqlConnection con = new SqlConnection(DB.GetDBConn()))
{
con.Open();
using (IDataReader dr = DB.GetRS("select CustomerName from Customer where CustomerID=" + Customer.CustomerID, con))
{
string CustomerName = "CustomerName";
}
}
String EncCustomerName = Encrypt(CustomerName.Replace(".", "").Replace("-", ""),"1");
Question #2: How do I bind the database content to the CustomerName string? It seems like its only returning "CustomerName" as the value for CustomerName string.. I would like it to return the database data for CustomerName string.. Help?
Suggested to use a ExecuteScalar, so i modified the request to this
using (var con = new SqlConnection(DB.GetDBConn()))
using (var cmdContrib = new SqlCommand("SELECT CustomerName FROM Customer WHERE CustomerID=" + ThisCustomer.CustomerID, con))
{
con.Open();
string CustomerName = cmdContrib.ExecuteScalar();
}
And i Get this error:
"string CustomerName = cmdCust.ExecuteScalar();"
CS0266: Cannot implicitly convert type 'object' to 'string'. An explicit conversion exists (are you missing a cast?)
To answer your second question:
// Set it here so you can access it outside the scope of the using statement
string CustomerName = "";
using (SqlConnection con = new SqlConnection(DB.GetDBConn()))
{
con.Open();
using (IDataReader dr = DB.GetRS("select CustomerName from Customer where CustomerID=" + Customer.CustomerID, con))
{
while (dr.Read())
CustomerName = dr["CustomerName"].ToString();
}
}
}
If you're sure you'll only get one CustomerName result, using a DataReader is a bit of an overkill.
SqlCommand.ExecuteScalar Example
string CustomerName = "";
using (SqlConnection con = new SqlConnection(DB.GetDBConn()))
{
SqlCommand cmd = new SqlCommand("SELECT CustomerName FROM Customer WHERE CustomerID = " + Customer.CustomerID, con);
cmd.CommandType = CommandType.Text;
con.Open();
CustomerName = Convert.ToString(cmd.ExecuteScalar());
}
SqlCommand.ExecuteScalar Method
Additional Info
ExecuteScalar returns an object, so you'll need to convert the returned value to the proper type (in this case, string).
Also, you should declare your CustomerName value outside of the using blocks (as I did in my example) - otherwise it will be scoped to the using blocks and not available outside of them.
It means that either CustomerName or CustomerID is not a valid column within your database. Check your table again.
Make sure you are trying to connect correct database.
See CustomerName column should be in Customer table. check spelling also
First, debug and check the value of:
DB.GetDBConn()
You will verify that you are going to the same in Studio as you are in the program.
I think it is the spelling somewhere between the db and your code.
Once you get past the error, you need to fix this:
{
string CustomerName = "CustomerName";
}
You are not accessing the reader, try some kind of tutorial for that stuff.
Try doing a select * from customer where ... and put a breakpoint on your using datareader statement. Then use quick-watch on the datareader object to investigate the columns exposed in the recordset.
Or you could run the select statement on your db of choice to ensure that the column name is the same.
I agree with Madhur above, your column name is not spelled correctly. Or you are not connecting to the correct db.
Hope this helps

circular reference in self-nested table 'firstname1'. asp.net

This is the error i am getting "circular reference in self-nested table 'firstname1'".
I want to Hierarchical Data binding. Employee and their supervisor are in the same table.
I am taking reference from http://weblogs.asp.net/alessandro/archive/2008/03/01/part-2-building-and-binding-hierarchical-data-from-the-database-to-the-asp-net-navigation-controls.aspx.
But it is giving error on generating Xml.
using (SqlConnection con = new SqlConnection(WebConfigurationManager.ConnectionStrings["RMSConnection"].ToString()))
{
string SqlCommand = "SELECT EmployeeId,FirstName,ReportToId FROM tblEmployee";
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = new SqlCommand(
SqlCommand, con);
adapter.Fill(ds);
ds.Tables[0].TableName = "FirstName1";
DataRelation dr = new DataRelation("pageId_parentId",ds.Tables["FirstName1"].Columns["EmployeeId"], ds.Tables["FirstName1"].Columns["ReportToId"]);
dr.Nested = true;
ds.Relations.Add(dr);
}
//string s= ds.GetXml();
above is my code.
Please Suggest.
You got an infinite loop in your table's data.
You are trying to make a link between EmployeeId and ReportToId but something is wrong.
Your problem is with all your row where the EmployeeId is equal to ReportToId
Exemple:
EmployeeId First Name ReportToId
1 Super 1
In all those cases, you need to set the ReportToId to Null
EmployeeId First Name ReportToId
1 Super Null

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));

Resources