I have a linq query:
var capacityQuery = from Info in mySQLDataTable.AsEnumerable()
where Info.Field<object>("location") == Location.ID
orderby Info.Field<DateTime>("date")
The line "where Info.Field("location") == Location.ID" is where I am having problems
My Question is. How do I do a comparison in the where statement that might be either a DBNull.Value or an int value on either side
Below is for reference:
Location is a custom class. The ID returns an object.
private int? addressID;
public object ID {
get
{
if (addressID == null)
return DBNull.Value;
else
return addressID;
}
}
The reason it has to be DBNull is because it is coming from a database. The "table" is also being filled in from a database.
I know == in this case is wrong because its comparing the references which is obviously false.
I know object.equal(var1, var2) should work but it doesnt which im guessing is because they are 2 different objects.
The values could be an int or DBNull both on the table side and the class side.
This is in a foreach loop so I use the same query where Location has an int value or when it has a DBNull value.
Again My Question is. How do I do a comparison in the where statement that might be either a DBNull.Value or an int value on either side
Use
private int? addressID;
public object ID {
get
{
return addressID.HasValue ? addressID.Value as object : DBNull.Value;
}
}
instead. This way, if addressID has not been initialized or if it has been deliberately set to null, the ID property will return a DBNull.Value. Otherwise, it will return an int, but you have to cast it yourself from object to int or int?.
Having said that, creation of the null has been called "a billion dollar mistake" by the author, but by now I think it is in the trillions. You should return an int? datatype from the database if you can, in which case, the comparison will always work. I am not sure which ORM do you use, but Dapper and linq2db handle this scenario correctly as far as I know.
Related
I am retrieving user information from a database using a simple query.
select * from dbo.[User] u where u.Email = #email
I then try to get the value of a column, called IsConfirmed (which is represented as a bit type column in the database) and convert it to bool.
bool isConfirmed = int.Parse(sqlDataReader["IsConfirmed"].ToString()) == 1;
I then get an FormatException error, stating that "Input string was not in a correct format.".
I saw a similar question with an answer providing this code:
bool isConfirmed = sqlDataReader.GetBoolean(0);
But this won't work with my case, because I don't know the index of the IsConfirmed column and I don't want to know it. I want to use the column name.
The value returned from the data reader indexer property is of type object but can be cast to the data type it has been stored as.
Try this:
bool isConfirmed = (bool)sqlDataReader["IsConfirmed"]
If you want to use the column name you can use
bool isConfirmed = sqlDataReader.GetBoolean(sqlDataReader.GetOrdinal("IsConfirmed"));
Your code should work if you don't have any null value in your column IsConfirmed.
Usually these bit columns have a NOT NULL property and/or a default value of 0, but it could happen to have a null value and, in this case, your code will fail with the error mentioned.
You could fix it in this way (You will need the column position for this check however)
int colPos = sqlDataReader.GetOrdinal("IsConfirmed");
bool isConfirmed = sqlDataReader.IsDBNull(colPos) ? false : sqlDataReader.GetBoolean(colPos));
If you really dislike to have a call to find the Column Position you could create an extension method that allow you to hide the call
public static class ReaderExtensions
{
public static bool IsDBNull(this SqlDataReader reader, string colName)
{
int colPos = reader.GetOrdinal(colName);
return reader.IsDBNull(colPos);
}
}
and call it with
bool isConfirmed = int.Parse((sqlDataReader.IsDBNull("IsConfirmed")
? "0" : sqlDataReader["IsConfirmed"].ToString())) == 1;
Try this: Convert.ToBoolean(reader["Columnname"]) or with Ordinal for example: Convert.ToBoolean((3))
For nullable boolean (if you may have null boolean values), you can try
bool? isConfirmed = sqlDataReader["IsConfirmed"] as bool?;
I have an error on return Convert.ToInt32(dataGridView1[0, Row].Value); it says that 'Object cannot be cast from DBNull to other types.' My database field on student ID is int. Here is my code:
public int GetStudentID()
{
// The Student ID is the first cell of the current row
int Row = dataGridView1.CurrentRow.Index;
return Convert.ToInt32(dataGridView1[0, Row].Value);
}
public string GetISBN()
{
// The ISBN is the second cell of the current row
int Row = dataGridView1.CurrentRow.Index;
return dataGridView1[1, Row].Value.ToString();
}
There a two possible problems here:
You are getting nulls from the database but always expecting a value
You are getting nulls from the database but not handling them
For problem 1, ensure the query that you're executing cannot allow null values. Maybe you're missing a filter...?
For problem 2, you need to check for null values:
public int GetStudentID()
{
int Row = dataGridView1.CurrentRow.Index;
var val = dataGridView1[0, Row].Value;
if (object.Equals(val, DBNull.Value))
{
/* either throw a more appropriate exception or return a default value */
// let's assume a default value is fine
return -1;
}
return Convert.ToInt32(val);
}
Your dataGridView1[0, Row].Value must be NULL
Check for NULL or use a try-catch block with NullReferenceException like below
try
{
return Convert.ToInt32(dataGridView1[0, Row].Value);
}
catch(NullReferenceException e)
{
return 0;//No such student ID when NULL is encountered.
}
You should check for DBNull.Value. It is not the same as null.
if(DBNull.Value != dataGridView1[0, Row].Value)
{
// do convertion, etc
}
else
{
// handle null case
}
It's handy to have a method to manage this little detail, e.g.:
email = Database.GetValueOrNull<string>(sqlCommand.Parameters["#Email"].Value);
Implemented like this:
public static T GetValueOrNull<T>(Object column)
{
// Convert DBNull values to null values for nullable value types, e.g. int? , and strings.
// NB: The default value for non-nullable value types is usually some form of zero.
// The default value for string is null .
// Sadly, there does not appear to be a suitable constraint ("where" clause) that will allow compile-time validation of the specified type <T>.
Debug.Assert(Nullable.GetUnderlyingType(typeof(T)) != null || typeof(T) == typeof(string), "Nullable or string types should be used.");
if (!column.Equals(DBNull.Value)) // Don't trust == when the compiler cannot tell if type <T> is a class.
return (T)column;
return default(T); // The default value for a type may be null . It depends on the type.
}
Moving data from a variable to a database parameter with null conversion may be accomplished thusly:
sqlCommand.Parameters.AddWithValue("#Serial", serial ?? (object)DBNull.Value);
I am on a C# ASP.NET project.
I have a MySQL table with a userid field of type int.
Now I want to get the number of rows where value of userid equals certain value using LINQ.
To achieve this, I wrote the following method:
public int getCount(int usercode) {
int count = 0;
DataTable mytable = getAllRowsAndReturnAsDataTable(); // assigning a DataTable value to mytable.
if (mytable.Rows.Count > 0) {
count = (from x in mytable.AsEnumerable() where x.Field<Int32>("userid") == usercode select x).Count();
}
return count;
}
but it is showing error System.InvalidCastException: Specified cast is not valid. showing count = (from x in mytable.AsEnumerable() where x.Field<Int32>("userid") == usercode select x).Count(); in red highlight area.
I don't know what I did wrong here. Please help.
The most likely cause of the InvalidCastException is the x.Field<Int32>("userid") line. The Field<T> extension method will throw an InvalidCastException in the case where the actual type of the data doesn't match the type which was passed to Field<T>. Hence if userid wasn't an Int32 this would throw.
EDIT
Based on your comments the type of userid is actually UInt32 and not Int32. This is what is causing the problem. Try using the following and it should work
x.Field<UInt32>("userid")
Without looking at the data coming back from your database I can only guess that the following part of your LINQ is at fault:
x.Field<Int32>("userid")
Your userid column value probably isn't an int, I would put my money on it being NULL?
UPDATE: Can you confirm it's not the Field call that is breaking? Simply change your code to something like this without the Field call:
public int getCount(int usercode){
int count = 0;
DataTable mytable = getAllRowsAndReturnAsDataTable(); // assigning a DataTable value to mytable.
if (mytable.Rows.Count > 0) {
count = mytable.AsEnumerable().Count(); // No WHERE function call so no casting.
}
return count;
}
You could also inspect what the values are that are returned by mytable.AsEnumerable() in a watch window for example to ensure that everything looks correct. If the code above works then it's the Field call blowing up. Find out which row cannot be cast to an Int32 and go from there.
If it is in fact NULL, there are a number of ways you can solve this.
Make sure you don't return NULL from your database query, in MySQL you can use IFNULL.
Use a nullable type for the generic being passed into Field:
where x.Field("userid") == (Int32?)usercode
How can I cast the result of an ExecuteScalar command to a GUID structure without first using .ToString() to pass to the constructor of the GUID?
The reason for doing this is performance and not creating thousands of unnecessary string objects in memory.
It is possible using a reader and the GetGUID Method but I can not see any references to how to achieve the same when using a scalar value.
Update: I also need to handle DBNull Values
Assuming that your sql statement cannot return DBNull.Value, then yes you can:
Guid myResult = (Guid) cmd.ExecuteScalar();
EDIT: Now that we know you need to handle nulls.... :-)
I can think of two ways to handle nulls - use a nullable Guid and set it to null, or use a regular Guid and have it set to Guid.Empty if your SQL statement returns null.
Consider some form of helper function or extension method which checks for DBNull.Value.
static Guid? GetGuidFromDb(object dbValue)
{
if (dbValue == null || DBNull.Value.Equals(dbValue))
{
return null;
}
else
{
return (Guid) dbValue;
}
}
or
static Guid GetGuidFromDb(object dbValue)
{
if (dbValue == null || DBNull.Value.Equals(dbValue))
{
return Guid.Empty;
}
else
{
return (Guid) dbValue;
}
Then call
Guid? myResult = GetGuidFromDb(cmd.ExecuteScalar());
Note - this will choke if your SQL command returns a datatype other than UniqueIdentifier.
If the object being returned from the command is a UniqueIdenitifier, then yes.
Guid myResult = cmd.ExecuteScalar() as Guid? ?? Guid.Empty;
I have a SQL query which returns only one field - an ID of type INT.
And I have to use it as integer in C# code.
Which way is faster and uses less memory?
int id;
if(Int32.TryParse(command.ExecuteScalar().ToString(), out id))
{
// use id
}
or
int? id = (int?)command.ExecuteScalar();
if(id.HasValue)
{
// use id.Value
}
or
int? id = command.ExecuteScalar() as int?;
if(id.HasValue)
{
// use id.Value
}
The difference between the three performance wise is negligible. The bottleneck is moving the data from the DB to your app, not a trivial cast or method call.
I would go with:
int? id = (int?)command.ExecuteScalar();
if(id.HasValue)
{
// use id.Value
}
It fails earlier, if one day people change the command to return a string or a date, at least it will crash and you will have a chance to fix it.
I would also just go with a simple int cast IF I always expected the command to return a single result.
Note, I usually prefer returning an out param than doing the execute scalar, execute scalar feels fragile (the convention that the first column in the first row is a return value does not sit right for me).
If you expect the command to return null, you should keep in mind that database null (DBNull) is not the same as .NET null. So, conversion of DBNull to int? would fail.
I'd suggest the following:
object result = command.ExecuteScalar();
int? id = (int?)(!Convert.IsDBNull(result) ? result : null);
If none of the above works (especially for users who are battling with MySQL)
why don't you try the following?
int id = Convert.ToInt32(cmd.ExecuteScalar().ToString());
int Result = int.Parse(Command.ExecuteScalar().ToString());
will work in C#.
The latter. Convert.ToInt32() is also an option.
Use id.HasValue for maximum Nullable Type cool-factor!
if ((Int32)cmd.ExecuteScalar () ** 1) //en esta parece qu esta el error pero no lo veo
{
Response.Redirect("Default.aspx");
}
else
{
Response.Redirect("error.htm") ;
}