commandtext parameter changes type when executing - c#

I have a problem in my c# application, when executing a commandtext on an ms-sql-server. Here is the function i use:
public T ExecuteScalar<T>(string commandText, IDbDataParameter[] parameters)
{
T result_value = default(T);
using (var connection = this.CreateConnection())
{
connection.Open();
using (var transaction = connection.BeginTransaction(IsolationLevel.ReadUncommitted))
{
using (var command = connection.CreateCommand())
{
command.Transaction = transaction;
command.CommandText = commandText;
command.CommandTimeout = this.CommandTimeOut;
if (parameters != null)
{
foreach (var parameter in parameters)
{
command.Parameters.Add(parameter);
}
}
object result = command.ExecuteScalar(); //Error is thrown here!
if (result is DBNull || result == null)
{
result_value = default(T);
}
else
{
Type type = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T);
if (type.IsEnum)
{
if (Enum.IsDefined(type, Int32.Parse(result.ToString())))
{
result_value =(T)Enum.Parse(type, result.ToString());
}
}
else
{
result_value = (T)Convert.ChangeType(result, type);
}
}
}
transaction.Commit();
}
}
return result_value;
}
The commandtext looks like this:
"insert into tbl_Person (Vorname,Nachname,Strasse,HausNr,PLZ,Ort) output inserted.id values (#Vorname,#Nachname,#Strasse,#HausNr,#PLZ,#Ort)"
Inspecting the parameters-property of my commandtext-object states out, that the HausNr-parameter has the following values:
db-type: string
sql-db-type: NVarChar
sql-value: {13/5}
value: "13/5"
So the HausNr-parameter should be a string right? But when executing the command, the following error is thrown:
"Fehler beim Konvertieren des nvarchar-Werts \"15/3\" in den
int-Datentyp."
Failed to convert the nvarchar-value \"15/3\" to the int-datatype
This looks like he is trying to convert the HausNr-parameter-value to an integer-value. Why does this happen?

The error message says that the database driver tries to convert yout string value to an integer value. The reason is that the column HausNr is an integer in your database.
So double check your database schema and change HausNr to an NVarChar.

Related

C# int? parameter- Data is Null. This method or property cannot be called on Null values

I am trying to call a stored procedure which has an INT parameter (BusinessID) and allows NULL. From my C# code, I can't figure out if data is null, how to identify and pass. I have listed three techniques I have tried numbered #1,#2,#3 and the errors I get. Please guide
Here is my sample code:
private static DataRow ValidateRecord (string ProjectNum, int? BusinessID)
{
DataRow returnRow = null;
using (SqlConnection connection = Connection.GetConnection())
{
if (connection.State != ConnectionState.Open)
{
connection.Open();
}
try
{
using (SqlCommand command = new SqlCommand(
"[dbo].[mySQLProc]", connection))
{
command.CommandType = CommandType.StoredProcedure;
command.CommandTimeout = 90;
command.Parameters.Add("#ProjectNum", SqlDbType.VarChar, 17).Value = ProjectNum;
// #1 – error: "Data is Null. This method or property cannot be called on Null values."
//if (!BusinessID.HasValue)
//{
// BusinessID = (int)System.Data.SqlTypes.SqlInt32.Null;
//}
//#2 - "Data is Null. This method or property cannot be called on Null values."
if (BusinessID == null)
{
BusinessID = (int)System.Data.SqlTypes.SqlInt32.Null;
}
//#3 - error on compile time – Type of conditional expression cannot be determined because
// there is no implicit converstion between ‘System.DBNull’ and ‘int?’
// BusinessID = BusinessID == null ? DBNull.Value : BusinessID;
command.Parameters.Add("#BusinessID", SqlDbType.Int).Value = BusinessID;
command.ExecuteNonQuery();
connection.Close();
returnRow = CreateDataRow(ProjectNum, BusinessID);
}
}
catch (Exception ex)
{
throw ex;
}
return returnRow;
}
}

Cannot insert null value in varbinary(max) with error : implicit conversion from data type nvarchar to varbinary(max) is not allowed

I want to insert null value in varbinary(max) but it is returning an error.
I am trying the code below to save the photo, when I attach photo it saves without any issue. When there is no photo it throws an error.
Implicit conversion from data type nvarchar to varbinary(max) is not
allowed. Use the CONVERT function to run this query.
protected void Button3_Click(object sender, EventArgs e)
{
newphoto pat = new newphoto();
pat.id = id.Text;
byte[] photo = null;
if (Attch.HasFile)
{
Stream fs2 = Attch.PostedFile.InputStream;
BinaryReader br2 = new BinaryReader(fs2);
pat.photo = br2.ReadBytes((Int32)fs2.Length);
}
else
{
pat.photo = null;
}
pat.Addfile()
}
public bool Addfile()
{
Parameters.Clear();
Parameters.AddWithValue("#pat_id", id);
if (photo == null)
{
Parameters.Add("#photo", SqlDbType.VarBinary, -1);
Parameters["#photo"].Value = DBNull.Value;
}
else
{
Parameters.AddWithValue("#photo", photo);
}
return FetchNonQuery(#"insert into mr_Info (#pat_id ,#photo)" +
" Values (#pat_id ,#photo)");
}
protected bool FetchNonQuery(string CmdQuery)
{
bool result = false;
using (SqlConnection myConnection = DBConnection)
{
SqlCommand myCommand = new SqlCommand(CmdQuery, myConnection);
myCommand.CommandType = CommandType.Text;
//Set Parameters
foreach (SqlParameter Parameter in _parameters)
{
myCommand.Parameters.AddWithValue(Parameter.ParameterName, Parameter.Value);
}
//Execute the command
myConnection.Open();
if (myCommand.ExecuteNonQuery() > 0)
{
result = true;
}
myConnection.Close();
}
return result;
}
This is a subtle bug caused by the AddWithValue call. (And not the only one).
When AddWithValue is able to correctly identify the type of the parameter you don't have a problem, but when you set the parameter value to DBNull.Value the method tries to convert this to a string and you get the error because the data field expects a VARBINARY.
However, when you build the parameter list, you are able to exactly specify the type expected and thus you can simply pass the parameter to the Add method instead of building another parameter with AddWithValue.
foreach (SqlParameter Parameter in _parameters)
{
myCommand.Parameters.Add(Parameter);
}
You can even remove the loop with
myCommand.Parameters.AddRange(_parameters.ToArray());
Also, as pointed in my other comment, the INSERT command should be written as
INSERT INTO (pat_id,photo) VALUES (#pat_id ,#photo)

SELECT query on Nvarchar column returning Int

I'm trying to return a string value from my database but instead the query is returning "0" although the SELECT query is targeting a nvarchar column.
The query is valid and runs correctly, returning "KYO" when run using SQL-SMS.
This is the method, which works as expected in the other place I use it, that I use for returning data:
public static object GetData(string sql, SqlParameter[] parameters)
{
try
{
using (DbConnection connection = factory.CreateConnection())
{
connection.ConnectionString = connectionString;
using (DbCommand command = factory.CreateCommand())
{
command.Connection = connection;
command.CommandType = CommandType.Text;
command.CommandText = sql;
if (parameters != null)
{
foreach (var parameter in parameters)
{
if (parameter != null)
command.Parameters.Add(parameter);
}
}
object result = null;
SqlParameter returnValue = new SqlParameter("ReturnValue", result);
returnValue.Direction = ParameterDirection.ReturnValue;
command.Parameters.Add(returnValue);
connection.Open();
command.ExecuteScalar();
result = command.Parameters["ReturnValue"].Value;
return result;
}
}
}
catch (Exception)
{
throw;
}
}
}
This is the method which is throwing a cast exception as it's returning an int instead of a string:
private static String GetManufacturerCode(Int32 manufacturerID)
{
try
{
StringBuilder sql = new StringBuilder();
sql.Append("SELECT ManufacturerCode FROM Manufacturers WHERE ManufacturerID = #ID");
SqlParameter id = new SqlParameter("#ID", manufacturerID);
return(String)DB.GetData(sql.ToString(), new[] { id });
}
catch (Exception)
{
throw;
}
}
I also set returnValue.DbType = DbType.String; as a test and this still returned an integer.
An example of where I use the GetData(...) method successfully is:
public static Int32 GetMonitoredCount()
{
try
{
String GetMonitoredCount = "SELECT COUNT(*) FROM Devices WHERE Monitored = 1 ";
return (Int32)DB.GetData(GetMonitoredCount, null);
}
catch (Exception)
{
throw;
}
}
I considered it might be returning a boolean bit but as my query executes correctly I'd have assumed it would return 1 not 0.
Why is an integer being returned? How can I return a string using my pattern?
ReturnValue always returns int - this is by design.
Instead of this entire block
object result = null;
SqlParameter returnValue = new SqlParameter("ReturnValue", result);
returnValue.Direction = ParameterDirection.ReturnValue;
command.Parameters.Add(returnValue);
connection.Open();
command.ExecuteScalar();
result = command.Parameters["ReturnValue"].Value;
Try
connection.Open();
object result = command.ExecuteScalar();
This will return you real result of your SQL statement
Method ExecuteScalar itself is capable of returning value - it return first column of the first row of the resultset and is ideal when your query returns a single value.

Error when receiving null from database

When i execute this command on my database i receive sometimes result=null. i want to enter the "else" part when is this happening, but i receive
An unhandled exception of type 'System.FormatException' occurred in mscorlib.dll.
Additional information: Input string was not in a correct format.
DB database = new DB();
int reservedSeats = 0;
using (database.sqlConnection)
{
database.sqlConnection.Open();
string command = "select SUM(nrLocuri) as result from Rezervari where idRand = #idRand and idShow=#idShow";
using (SqlCommand cmd = new SqlCommand(command, database.sqlConnection))
{
cmd.Parameters.Add("#idRand", SqlDbType.Int).Value = idRand;
cmd.Parameters.Add("#idShow", SqlDbType.Int).Value = idShow;
using (SqlDataReader dr = cmd.ExecuteReader())
{
if (dr.Read())
if (dr["result"].ToString() != null)
reservedSeats = Convert.ToInt32(dr["result"].ToString());
else
return totalSeats;
}
}
}
return totalSeats-reservedSeats;
Instead of:
if (dr["result"].ToString() != null)
Do:
if (dr["result"] != DbNull.Value)
When the dr["result"] returns a database null, its value is DbNull.Value - when you try to call Convert.ToInt32 on this value, you get a format exception.
try:
if(!dr.IsDBNull(i)){ //replace i with the column id
//get the data
}
If you want SUM() to return 0.00 in the event no records were found, replace it with:
COALESCE(SUM(...), 0.00)
COALESCE will return the first non-null value passed to it.
try isnull:
string command = "select isnull(SUM(nrLocuri),0.00 )as result from Rezervari where idRand = #idRand and idShow=#idShow";

Read data from SqlDataReader

I have a SQL Server 2008 database and I am working on it in the backend. I am working on asp.net/C#
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
//how do I read strings here????
}
I know that the reader has values. My SQL command is to select just 1 column from a table. The column contains strings ONLY. I want to read the strings (rows) in the reader one by one. How do I do this?
using(SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
var myString = rdr.GetString(0); //The 0 stands for "the 0'th column", so the first column of the result.
// Do somthing with this rows string, for example to put them in to a list
listDeclaredElsewhere.Add(myString);
}
}
string col1Value = rdr["ColumnOneName"].ToString();
or
string col1Value = rdr[0].ToString();
These are objects, so you need to either cast them or .ToString().
Put the name of the column begin returned from the database where "ColumnName" is. If it is a string, you can use .ToString(). If it is another type, you need to convert it using System.Convert.
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
string column = rdr["ColumnName"].ToString();
int columnValue = Convert.ToInt32(rdr["ColumnName"]);
}
while(rdr.Read())
{
string col=rdr["colName"].ToString();
}
it wil work
Thought to share my helper method for those who can use it:
public static class Sql
{
public static T Read<T>(DbDataReader DataReader, string FieldName)
{
int FieldIndex;
try { FieldIndex = DataReader.GetOrdinal(FieldName); }
catch { return default(T); }
if (DataReader.IsDBNull(FieldIndex))
{
return default(T);
}
else
{
object readData = DataReader.GetValue(FieldIndex);
if (readData is T)
{
return (T)readData;
}
else
{
try
{
return (T)Convert.ChangeType(readData, typeof(T));
}
catch (InvalidCastException)
{
return default(T);
}
}
}
}
}
Usage:
cmd.CommandText = #"SELECT DISTINCT [SoftwareCode00], [MachineID]
FROM [CM_S01].[dbo].[INSTALLED_SOFTWARE_DATA]";
using (SqlDataReader data = cmd.ExecuteReader())
{
while (data.Read())
{
usedBy.Add(
Sql.Read<String>(data, "SoftwareCode00"),
Sql.Read<Int32>(data, "MachineID"));
}
}
The helper method casts to any value you like, if it can't cast or the database value is NULL, the result will be null.
For a single result:
if (reader.Read())
{
Response.Write(reader[0].ToString());
Response.Write(reader[1].ToString());
}
For multiple results:
while (reader.Read())
{
Response.Write(reader[0].ToString());
Response.Write(reader[1].ToString());
}
I know this is kind of old but if you are reading the contents of a SqlDataReader into a class, then this will be very handy. the column names of reader and class should be same
public static List<T> Fill<T>(this SqlDataReader reader) where T : new()
{
List<T> res = new List<T>();
while (reader.Read())
{
T t = new T();
for (int inc = 0; inc < reader.FieldCount; inc++)
{
Type type = t.GetType();
string name = reader.GetName(inc);
PropertyInfo prop = type.GetProperty(name);
if (prop != null)
{
if (name == prop.Name)
{
var value = reader.GetValue(inc);
if (value != DBNull.Value)
{
prop.SetValue(t, Convert.ChangeType(value, prop.PropertyType), null);
}
//prop.SetValue(t, value, null);
}
}
}
res.Add(t);
}
reader.Close();
return res;
}
I would argue against using SqlDataReader here; ADO.NET has lots of edge cases and complications, and in my experience most manually written ADO.NET code is broken in at least one way (usually subtle and contextual).
Tools exist to avoid this. For example, in the case here you want to read a column of strings. Dapper makes that completely painless:
var region = ... // some filter
var vals = connection.Query<string>(
"select Name from Table where Region=#region", // query
new { region } // parameters
).AsList();
Dapper here is dealing with all the parameterization, execution, and row processing - and a lot of other grungy details of ADO.NET. The <string> can be replaced with <SomeType> to materialize entire rows into objects.
Actually, I figured it out myself that I could do this:
while (rdr.read())
{
string str = rdr.GetValue().ToString().Trim();
}
In the simplest terms, if your query returns column_name and it holds a string:
while (rdr.Read())
{
string yourString = rdr.getString("column_name")
}
I usually read data by data reader this way. just added a small example.
string connectionString = "Data Source=DESKTOP-2EV7CF4;Initial Catalog=TestDB;User ID=sa;Password=tintin11#";
string queryString = "Select * from EMP";
using (SqlConnection connection = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand(queryString, connection))
{
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
Console.WriteLine(String.Format("{0}, {1}", reader[0], reader[1]));
}
}
reader.Close();
}
}
You have to read database columnhere. You could have a look on following code snippet
string connectionString = ConfigurationManager.ConnectionStrings["NameOfYourSqlConnectionString"].ConnectionString;
using (var _connection = new SqlConnection(connectionString))
{
_connection.Open();
using (SqlCommand command = new SqlCommand("SELECT SomeColumnName FROM TableName", _connection))
{
SqlDataReader sqlDataReader = command.ExecuteReader();
if (sqlDataReader.HasRows)
{
while (sqlDataReader.Read())
{
string YourFirstDataBaseTableColumn = sqlDataReader["SomeColumn"].ToString(); // Remember Type Casting is required here it has to be according to database column data type
string YourSecondDataBaseTableColumn = sqlDataReader["SomeColumn"].ToString();
string YourThridDataBaseTableColumn = sqlDataReader["SomeColumn"].ToString();
}
}
sqlDataReader.Close();
}
_connection.Close();
I have a helper function like:
public static string GetString(object o)
{
if (o == DBNull.Value)
return "";
return o.ToString();
}
then I use it to extract the string:
tbUserName.Text = GetString(reader["UserName"]);

Categories