Specified cast is not valid when I try to cast to (int?) - c#

I have this code to save data to database
for (int i = 0; i < dt.Rows.Count; i++)
{
var row = dt.Rows[i];
await stock.AddProjectNeedsBoltsTest(Convert.ToInt32(row["Quantité"]),
(int?)row["Filetage"],
Convert.ToInt32(row["idProject"]),
(int?)row["idCategory"],
(int?)row["idType"]).ConfigureAwait(true);
}
and this the code behind AddProjectNeedsBoltsTest
public async Task AddProjectNeedsBoltsTest(int Quantity, int? Filetage, int IdProject, int? IdCategory, int? IdType)
{
DAL.DataAccessLayer DAL = new DAL.DataAccessLayer();
await Task.Run(() => DAL.Open()).ConfigureAwait(false);
SqlParameter[] param = new SqlParameter[5];
param[0] = new SqlParameter("#Quantity", SqlDbType.Int)
{
Value = Quantity
};
param[1] = new SqlParameter("#Filetage", SqlDbType.Int)
{
Value = Filetage.HasValue ? Filetage : (object)DBNull.Value
};
param[2] = new SqlParameter("#IdProject", SqlDbType.Int)
{
Value = IdProject
};
param[3] = new SqlParameter("#IdCategory", SqlDbType.Int)
{
Value = IdCategory.HasValue ? IdCategory : (object)DBNull.Value
};
param[4] = new SqlParameter("#IdType", SqlDbType.Int)
{
Value = IdType.HasValue ? IdType : (object)DBNull.Value
};
await Task.Run(() => DAL.ExcuteCommande("AddProjectNeedsBoltsTest", param)).ConfigureAwait(false);
DAL.Close();
}
and this is my stored procedure
CREATE PROCEDURE dbo.AddProjectNeedsBoltsTest
#Quantity int
,#Filetage int
,#IdProject int
,#IdCategory int
,#IdType int
AS
INSERT INTO [dbo].[ProjectNeedsBolts]
([Quantity]
,[Filetage]
,[IdProject]
,[IdCategory]
,[IdType])
VALUES
(#Quantity
,#Filetage
,#IdProject
,#IdCategory
,#IdType)
Now when I click on save button I get this error
An exception of type 'System.InvalidCastException' occurred in Smart Industrial Management.exe but was not handled in user code
Additional information: Specified cast is not valid.
On debugging on this line of code
(int?)row["Filetage"]
I get this error message
Cannot unbox 'row["Filetage"]' as a 'int?'
Update:This is my datatable
DataTable dt = new DataTable();
void CreateDataTable()
{
dt.Columns.Add("Quantité");
dt.Columns.Add("Filetage");
dt.Columns.Add("idProject");
dt.Columns.Add("idCategory");
dt.Columns.Add("idType");
gridControl1.DataSource = dt;
}
If I try with
dt.Columns.Add("Filetage", typeof(int?));
I get error message
DataSet does not support System.Nullable<>

Indeed, DataTable doesn't support int? - you'd add it as an int - with DataTable handing nullability separately. For the cast, there are two possibilities:
the value is DBNull
the value is something else - not an int; perhaps a long or a string
For 1 - just check whether the value is DBNull, and if so: don't try casting it to an int - handle the null yourself.
For 2 - you'd have to do your own parsing / conversion code, but frankly: it would be better to fix the database so that it is right
However, frankly: I am going to say: tools like Dapper make this just go away - no DataTable, no worries. You'd just use things like a List<ProjectNeedsBolts> for POCO:
public class ProjectNeedsBolts {
public int Quantity {get;set;}
public int IdType {get;set;}
}
(or int?, or whatever else you need), then get the library to do all the work for you:
await conn.ExecuteNonQueryAsync(
"AddProjectNeedsBoltsTest",
new { Quantity, Filetage, IdProject, IdCategory, IdType }
commandType: CommandType.StoredProcedure).ConfigureAwait(false);
or:
var data = await conn.QueryAsync<ProjectNeedsBolts>(
"your select sql",
new {...} // parameters
}).ConfigureAwait(false);

Related

c#: How do create a null INT to use as an SQL Parameter

I'm declaring some variables then
I'm looping through some data using switch command if an attribute exists it gets assigned to the relevant variable
It is possible age will not be found the PostgreSQL Table reflects this
CREATE my_table(
id SERIAL PRIMARY KEY,
name varchar,
age INTEGER
);
The code snippet is giving me errors
Use of unassigned local variable 'age'
Argument 2: cannot convert from 'out int?' to 'out int'
Cannot convert type 'System.DBNull' to 'int'
How do I declare a null int and maybe assign a value if not pass it to the database as null?
IN pseudo code to show the gist of what I'm doing
// declared at the same level
string name = string.Empty;
int? age;
foreach (var p in Feature.Properties)
{
var Key = p.Key;
var Value = p.Value;
switch (Key.ToLower())
{
case "name":
{
name = Value;
break;
}
case "age":
{
// May not exist
// Err 2
int.TryParse(Value, out age);
break;
}
}
}
// Err 1 name is OK
Console.WriteLine(name + age);
using (var DB_con = new NpgsqlConnection(cs))
{
var sql = "INSERT INTO my_table (name,age )VALUES "+
"(#p_name, #p_age RETURNING id;";
using (var cmd = new NpgsqlCommand(sql, DB_con))
{
cmd.CommandType = System.Data.CommandType.Text;
cmd.Parameters.AddWithValue("#p_name", name);
// Err 3
cmd.Parameters.AddWithValue("#p_age", age ?? (int)DBNull.Value );
DB_con.Open();
var res = cmd.ExecuteScalar();
DB_con.Close();
}
}
I see two problems in your code:
you are trying to use int.TryParse() with nullable int.
you are trying to cast DBNull.Value into int.
please try something like this:
// declared at the same level
string name = string.Empty;
int? age;
foreach (var p in Feature.Properties)
{
var Key = p.Key;
var Value = p.Value;
switch (Key.ToLower())
{
case "name":
{
name = Value;
break;
}
case "age":
{
// May not exist
// Err 2
int parsedAge;
//try parsing into int, when sucessfull then assing value
if(int.TryParse(Value, out parsedAge))
{
age = parsedAge;
}
break;
}
}
}
// Err 1 name is OK
Console.WriteLine(name + age);
using (var DB_con = new NpgsqlConnection(cs))
{
var sql = "INSERT INTO my_table (name,age )VALUES "+
"(#p_name, #p_age RETURNING id;";
using (var cmd = new NpgsqlCommand(sql, DB_con))
{
cmd.CommandType = System.Data.CommandType.Text;
cmd.Parameters.AddWithValue("#p_name", name);
// Err 3
//remove casting into int
cmd.Parameters.AddWithValue("#p_age", age ?? DBNull.Value );
DB_con.Open();
var res = cmd.ExecuteScalar();
DB_con.Close();
}
}

How to check passport number exist or not?

I want to check passport number exist or not ,
before I used this code to check if integer number exist or not ,
but passport number column in MSSQL type varchar(50).
what I tried
1- created stored procedure to read ID No :
create proc [dbo].[VALIDATE_PATIENT_IDNO]
#patient_id varchar(50)
as
select Patient_id from Patients
where Patient_id = #patient_id
2- I created this code in C# to validate id no exist or not :
public int? VALIDATE_PATIENT_IDNO(string patient_id)
{
DAL.DataAccessLayer DAL = new DAL.DataAccessLayer();
DataTable dt = new DataTable();
SqlParameter[] Param = new SqlParameter[1];
Param[0] = new SqlParameter("#patient_id", SqlDbType.VarChar,50);
Param[0].Value = patient_id;
dt = DAL.SelectData("VALIDATE_PATIENT_IDNO", Param);
DAL.close();
if (dt.Rows.Count > 0)
{
DataRow row = dt.Rows[0];
int? patientNumber = row.Field<int>("patient_id");
return patientNumber;
}
// return null otherwise
return null;
}
3- when type the id no or passport no when key down code :
private void textIDNO_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
if (string.IsNullOrEmpty(textIDNO.Text))
{
txtpcfileno.Focus();
}
else
{
var patientNumber = patient.VALIDATE_PATIENT_IDNO(textIDNO.Text); // int?
bool patientExists = patientNumber.HasValue;
if (patientExists == true)
{
MessageBox.Show("Id or Passport No Exist ", "ID EXIST", MessageBoxButtons.OK, MessageBoxIcon.Stop);
return;
}
else
{
txtpcfileno.Focus();
}
}
}
}
4- I have error appeared in the code in step 2 :
Additional information: Specified cast is not valid.
int? patientNumber = row.Field<int>("patient_id");
How to change the code in step 2 and solve this error and check string value not int? ?
Letting the naming confusions (passportnumber vs patientid) aside, you probably don't want to return the found patientids (because you already know them, as they are part of your selection condition) but the count.
Furthermore, your patientid seems to be a string, yet in your result you try to cast this to an integer. That is not possible, thus the error.
You can try as follows:
create proc [dbo].[VALIDATE_PATIENT_IDNO]
#patient_id varchar(50)
as
select count(Patient_id) as patientcount from Patients
where Patient_id = #patient_id
Assuming that patient_id is the primary key of your table, this will either return 1 if a row with the given id exists or 0 if not.
Then you can do
int? patientNumber = row.Field<int>("patientcount");
and then
bool patientExists = patientNumber > 0;

Pass DateTimePicker Value to a stored procedure C#

I have DataGridView and DateTimePicker and I want to show data in DataGridView based on DateTimePicker value.
Here is the stored procedure:
create proc Get_Employers_All_Day
#Date_Day date
as
SELECT
[Employer_ID] as 'رقم الموظف'
, Employer_Name as 'اسم الموظف'
FROM [dbo].[Come_Out]
inner join Employers
on Employers .Epmloyer_ID = Come_Out .Employer_ID
where
Come_Out .Status = '2'
and Come_Out .Data_Come_Out = #Date_Day
Here is the C# code:
public void Get_Employers_All_Day(DateTime Date_Day)
{
DAL.DataAccessLayer DAL = new DAL.DataAccessLayer();
DAL.Open();
SqlParameter[] param = new SqlParameter[1];
param[0] = new SqlParameter("#Date_Day", SqlDbType.DateTime);
param[0].Value = Date_Day;
DAL.ExecuteCommand("Get_Employers_All_Day", param);
DAL.Close();
}
and the event :
private void Frm_Daily_Come_Out_Load(object sender, EventArgs e)
{
BL.Employers emp = new BL.Employers();
dataGridView1.DataSource = emp.Get_Employers_All_Day(dateTimePicker1 .Value );
}
The error is:
cannot implicitly convert type 'void' to 'object'
Your Get_Employers_All_Day() method has a return type of void, meaning it has no return type.
Modify it to return the data you need. If your DAL.ExecuteCommand() returns a DataTable, for example, modify it to return that:
public DataTable Get_Employers_All_Day(DateTime Date_Day)
{
...
...
DataTable result;
try
{
result = DAL.ExecuteCommand("Get_Employers_All_Day", param);
}
finally
{
// Even if ExecuteCommand() fails, close any open connections
DAL.Close();
}
return result;
}

SQLite reports insert query error even though the row inserted

I am using http://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki version 1.0.82.0
When I insert a row like so:
"INSERT INTO [testtable] (col1,col2) values ('','')"
I always get a result of 1 from SQLiteCommand.ExecuteNonQuery(); where it should be returning 0 (OK) or 101 (DONE). I know the row is getting inserted just fine because the auto increment value increases each time I run the method.
The class
readonly object _threadlock = new object();
readonly string _file;
public CSQLite(string file)
{
_file = file;
}
private SQLiteConnection _sqlCon;
private SQLiteCommand _sqlCmd;
private SQLiteDataAdapter _db;
private void SetConnection()
{
lock (_threadlock)
{
_sqlCon = new SQLiteConnection(String.Format("Data Source={0};Version=3;New=False;Compress=True;", _file));
}
}
public int SimpleInsertAndGetlastID(out int id)
{
lock (_threadlock)
{
SetConnection();
_sqlCon.Open();
//Execute
_sqlCmd = _sqlCon.CreateCommand();
_sqlCmd.CommandText = "INSERT INTO [testtable] (col1,col2) values ('','')";
var res = _sqlCmd.ExecuteNonQuery();
//Get id
_db = new SQLiteDataAdapter("select last_insert_rowid();", _sqlCon);
var ds = new DataSet();
_db.Fill(ds);
DataTable dt = ds.Tables[0];
var val = dt.Rows[0][0].ToString();
Int32.TryParse(val, out id);
_sqlCon.Close();
return res;
}
}
The Test:
/// <summary>
///A test for SimpleInsertAndGetlastID
///</summary>
[TestMethod()]
public void SimpleInsertAndGetlastIDTest()
{
var file = "dbs\\test.db";
var target = new CSQLite(file);
var id = -1;
var res = -1;
try
{
res = target.SimpleInsertAndGetlastID(out id);
}
catch (Exception ex){/*Breakpoint*/}
Assert.IsTrue(id > 0); //id gets +1 every time the test is run so the row *is* getting inserted
Assert.IsTrue(res==0||res==101); //Res is always 1 for some reason
}
Table creation (in case that's the problem):
public List<string> Columns { get; set; }
if (!File.Exists(_dbFile))
SQLiteConnection.CreateFile(_dbFile);
var fieldqry = "";
var count = 0;
Columns.ForEach((field) =>
{
count++;
fieldqry += String.Format("[{0}] TEXT NULL", field);
if (count < Columns.Count)
fieldqry += ",";
});
var qry = String.Format("CREATE TABLE IF NOT EXISTS [{0}](" +
"[ID] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT," +
"{1}" +
");", TableName, fieldqry);
var sql = new CSQLite(_dbFile);
var res = sql.Execute(qry);
if(res!=SqLiteErrorCodes.SQLITE_OK)
throw new SqLiteImplementationException("Query failed.");
Where columns is new List<string> { "col1", "col2" } };
Can anyone tell me what I did wrong?
ExecuteNonQuery() does not return a SQLite error code, it returns the number of rows affected by the query. If you are inserting a row, 1 sounds like the expected result if the operation was successful.
The result from ExecuteNonQuery is concidered as "number of rows affected" and not an error code :-)

In Ado.Net, can I determine if columns in result sets are nullable?

I need to determine the structure of a result set returned by ExecuteReader. I am using the following approach:
public List<NameAndType> ResultSetStructure(DataTable columns)
{
var ret = new List<NameAndType>();
foreach (DataRow column in columns.Rows)
{
ret.Add(new NameAndType { Name = column[NameIndex].ToString(),
Type = column[TypeIndex].ToString()
});
}
return ret;
}
(snip)
using (SqlDataReader dr = command.ExecuteReader())
{
var rawColumns = dr.GetSchemaTable();
var columns = ResultSetStructure(rawColumns);
This gives me column names and types, but I would also like to know if the column is nullable, so that I know which of the following options to choose:
decimal density = dr.GetDecimal(0);
decimal? density = dr.IsDBNull(0) ? (decimal?)null : dr.GetDecimal(0);
Can I accomplish that? TIA.
Edit: I just found what I need:
column[13].ToString()
I guess there is no such way to know whether a column is nullable or not. You can try writing an extension method something like below:
public static decimal GetDecimal(this SqlDataReader reader, int columnIndex)
{
if(!reader.IsDBNull(columnIndex))
{
return reader.GetDecimal(colIndex);
}
else
{
return 0;
}
}
Hope this would be some help!!
The following code gets the job done:
ret.Add(new NameAndType { Name = column[NameIndex].ToString(),
Type = column[TypeIndex].ToString(),
IsNullable = column[13].ToString().Equals("True")

Categories

Resources