SqlParameter Cast in C# - c#

I have a SqlParameter contained in a var coming back from a stored procedure and the value is either Null, an int or -1. How do cast the var to check if it is -1 in C#?
var p_eventID = new SqlParameter()
{
ParameterName = "#EventID",
Value = (eventID.HasValue
? (object)eventID.Value
: (object)System.Data.SqlTypes.SqlInt32.Null),
Direction = ParameterDirection.InputOutput
};
I have tried:
if ((int?)eventID.Value == -1)
But it gives me an invalid cast error.

SQL requests report NULLs to C# through DBNull objects, forcing the cast to fail.
You can do the other kind of cast to int? without triggering an error:
var eventIdInt = eventId as int?;
if (eventIdInt == -1) {
...
}
Rather than throwing an exception, the x as type style of cast would produce a null value when the cast fails.

Your approach when an error occurs, it will throw an Invalid Cast Exception. However, if you utilize the as int if it fails it will return a null. Which will be a bit more graceful, and forgiving.
So you could do the following:
if(eventId != null)
{
// Do Stuff.
}
So that returned value from your scalar, should either contain an actual int or a null.
So in order to solve why you receive the error with the (int) we would need to see how you implement the scalar and know the type of object it is actually returning before the cast.

Related

LINQ: Nullable object must have a value [duplicate]

There is paradox in the exception description:
Nullable object must have a value (?!)
This is the problem:
I have a DateTimeExtended class,
that has
{
DateTime? MyDataTime;
int? otherdata;
}
and a constructor
DateTimeExtended(DateTimeExtended myNewDT)
{
this.MyDateTime = myNewDT.MyDateTime.Value;
this.otherdata = myNewDT.otherdata;
}
running this code
DateTimeExtended res = new DateTimeExtended(oldDTE);
throws an InvalidOperationException with the message:
Nullable object must have a value.
myNewDT.MyDateTime.Value - is valid and contain a regular DateTime object.
What is the meaning of this message and what am I doing wrong?
Note that oldDTE is not null. I've removed the Value from myNewDT.MyDateTime but the same exception is thrown due to a generated setter.
You should change the line this.MyDateTime = myNewDT.MyDateTime.Value; to just this.MyDateTime = myNewDT.MyDateTime;
The exception you were receiving was thrown in the .Value property of the Nullable DateTime, as it is required to return a DateTime (since that's what the contract for .Value states), but it can't do so because there's no DateTime to return, so it throws an exception.
In general, it is a bad idea to blindly call .Value on a nullable type, unless you have some prior knowledge that that variable MUST contain a value (i.e. through a .HasValue check).
EDIT
Here's the code for DateTimeExtended that does not throw an exception:
class DateTimeExtended
{
public DateTime? MyDateTime;
public int? otherdata;
public DateTimeExtended() { }
public DateTimeExtended(DateTimeExtended other)
{
this.MyDateTime = other.MyDateTime;
this.otherdata = other.otherdata;
}
}
I tested it like this:
DateTimeExtended dt1 = new DateTimeExtended();
DateTimeExtended dt2 = new DateTimeExtended(dt1);
Adding the .Value on other.MyDateTime causes an exception. Removing it gets rid of the exception. I think you're looking in the wrong place.
When using LINQ extension methods (e.g. Select, Where), the lambda function might be converted to SQL that might not behave identically to your C# code. For instance, C#'s short-circuit evaluated && and || are converted to SQL's eager AND and OR. This can cause problems when you're checking for null in your lambda.
Example:
MyEnum? type = null;
Entities.Table.Where(a => type == null ||
a.type == (int)type).ToArray(); // Exception: Nullable object must have a value
Try dropping the .value
DateTimeExtended(DateTimeExtended myNewDT)
{
this.MyDateTime = myNewDT.MyDateTime;
this.otherdata = myNewDT.otherdata;
}
Assign the members directly without the .Value part:
DateTimeExtended(DateTimeExtended myNewDT)
{
this.MyDateTime = myNewDT.MyDateTime;
this.otherdata = myNewDT.otherdata;
}
In this case oldDTE is null, so when you try to access oldDTE.Value the InvalidOperationException is thrown since there is no value. In your example you can simply do:
this.MyDateTime = newDT.MyDateTime;
Looks like oldDTE.MyDateTime was null, so constructor tried to take it's Value - which threw.
I got this message when trying to access values of a null valued object.
sName = myObj.Name;
this will produce error. First you should check if object not null
if(myObj != null)
sName = myObj.Name;
This works.
I got this solution and it is working for me
if (myNewDT.MyDateTime == null)
{
myNewDT.MyDateTime = DateTime.Now();
}

Initialize dynamically the var filter

What I'm trying to achieve is to initialize the "filter" variable dynamically based on what my method gets.
Initializing it to null throws an error.
Leaving it empty throws error.
Setting it to a generic type throws an error
Setting it to a new BsonDocument also throws an error
This is my code:
var filter=null;
if (id != 0)
if (subID != 0)
//Get Specific Categories
filter = builder.Eq("Categories.Sub.id", id) & builder.Eq("Categories.Sub.Custom.id", subID);
else
//Get SubCategories
filter = builder.Eq("Categories.Sub.id", id);
else
//Get Generic Categories
filter = new BsonDocument();
I've been searching but nobody seems to have my problem or I'm not able to find it.
Var is not a dynamic variable, it is a keyword for type inference. These are very different concepts. The key issue is that in your code snippet the compiler can not figure out what kind of variable you want your var to be.
var myNumber = 3; // myNumber is inferred by the compiler to be of type int.
int myNumber = 3; // this line is considered by the computer to be identical to the one above.
The inferred type of a var variable does not change.
var myVariable = 3;
myVariable = "Hello"; // throws an error because myVariable is of type int
The type of dynamic variables can change.
dynamic myVariable = 3;
myVariable = "Hello"; // does not throw an error.
The compiler must be able to determine the type of an object when a var variable is created;
var myVariable = null; // null can be anything, the compiler can not figure out what kind of variable you want.
var myVariable = (BsonDocument)null; // by setting the variable to a null instance of a specific type the compiler can figure out what to set var to.
With var it's an implicit type and you can initialize a implicit type variable to null since it can be both value type and reference type; and value type can't be assigned to null (unless otherwise it's made nullable explicitly).
Thus instead of saying var filter=null; you should explicitly specify the type
BsonDocument filter = null;

linq to entity query getting error

I am trying to amend a c# project. I am a vb.vet programmer so having a few issues as I am new to linq. I am trying to run a Linq to Entity query. I want to select the MapEast where town = town. I keep get an error The specified cast from a materialized System.Decimal' type to the 'System.Int32' type is not valid.. I would like to put a max(1) in here too so it returns only the highest number.
var topEast = 0;
try
{
topEast = this._uow.Addresses
.Where(a =>
a.Town.Trim().ToUpper() == town.Trim().ToUpper())
.Select(m => m.MapEast).FirstOrDefault ();
return -1;
}
catch
{
return -1;
}
Thanks
var is used for implicitly typed local variable. When you defined var topEast = 0;, topEast was implicitly assigned type int, and not decimal as per your query. You can fix it by explicitly defining topEast as decimal.
decimal topEast = 0;
I would like to put a max(1) in here too so it returns only the
highest number.
Not really sure what you are trying to return, because you are returning -1 from try as well as catch block. If you are trying to return the Max value of MapEast field then you will need Enumerable.Max, otherwise FirstOrDefault would return the first item or null based on criteria.

Why was I let assign a null value to a bool? What's the best way to resolve this?

I have a Linq to SQL query very similar to the following:
var result = (from shareclass in database.ShareClassInfo
where shareclass.Id == ID
select new ShareClass
{
IsOnlineListing = shareclass.IsOnlineListing
}
);
var list = result.ToList();
When I try to create a list from the results I get the following error:
The null value cannot be assigned to a member with type System.Boolean which is a non-nullable value type.
The reason for this is that IsOnlineListing is a bool, but the field in the database is null. So I'm effectively trying to assign a value type with a null value (which is impossible).
I think the solution to this is to make IsOnlineListing a nullable type, but I'm a little confused why I was let do this in the first place. I mean, the database field is defined as a [bit] NULL field. I thought the compiler would be smarter than to let me assign null value to a non-nullable type, or at least it would warn me about it.
So what I'm wondering, is if this is the correct solution? Is there another way to do this? Why wasn't the compiler able to tell me that this is or could be a problem?
you need to change your declaration of IsOnlineListing
From
bool IsOnlineListing;
To
bool? IsOnlineListing;
Or do something like this
var result = (from shareclass in database.ShareClassInfo
where shareclass.Id == ID
select new ShareClass
{
IsOnlineListing = shareclass.IsOnlineListing.HasValue ?
shareclass.IsOnlineListing.Value : false;
}
);
var list = result.ToList();
You can use a nullable type.

casting problem from SqlDataReader

Suppose i have this sql statement and I have executed a sql command to get a datareader:
"select 1 union select 2"
//.....
var rdr = cmd.ExecuteReader();
and now i want to read the value in the first column of the first row:
var myInt = (int)rdr.GetValue(0); //great this works
var myLong = (long)rdr.GetValue(0); //throws cast exception, even though you can cast int to long
So it appears the type you cast to in C# needs to match exactly the SQL type. I.E. If the sql type is bigint, you can only cast to long. If the sql type is int, you can only cast to int. No mix and match...
I just want to get something that works regardless of the type of integer c# asks for and sql returns, as long as you could theoretically cast one to the other. So if SQL Server gives me a floating point type, and I'm asking for an int, I want the truncated int you get from doing that cast.
My goal is to make this work with generics, so I can have this function work when the generic parameter doesn't exactly match the datatype in sql server:
List<T> GetFirstColumn<T>(string sql) where T : struct
{
//get connection, execute reader
// loop:
// lst.Add( (T) rdr.GetValue(0));
}
I'd like this to work for both statments:
var sql1 = "Select 1"; //sql int
var sql2 = "Select cast(1 as bigint)"; //sql equivalent of a long
var lst1 = GetFirstColumn<int>(sql1);
var lst2 = GetFirstColumn<int>(sql2);
Does anyone have a relatively painless way of doing this?
Like Fredrik says, the value from SqlDataReader is boxed. You can convert a boxed value to an int with Convert.ToInt32, like:
int i = Convert.ToInt32(read[0]);
This will try to convert even if SQL Server returns a bigint or a decimal.
System.Convert will take care of the conversion.
T GetValue<T>(SqlDataReader rdr)
{
var dbVal = rdr.GetValue(0);
var csVal = (T)System.Convert.ChangeType(dbVal, typeof(T));
}
Caveat: if T == Nullable<S>, you need to do some extra work with reflection to get the underlying type and call ChangeType with typeof(S) as the type parameter. Apparently, MS didn't update the ChangeType function with .NET 2.0 and the introduction of nullables. And if it's a nullable, and dbVal is DBNull, you can just return null.
object dbValue = 5;
//this throws
Convert.ChangeType(dbValue, typeof(int?));
//this works
if(dbValue == DBNull.Value || dbValue == null)
{
if(typeof(int?).IsNullable) //or is a class, like string
{return null;}
dbValue = null;
}
var type = GetUnderlyingType<int?>(); //== typeof(int)
Convert.ChangeType(dbValue, type);
I think your problem is that GetValue returns an object. This means that in the case of an int, you will get an int boxed in an object. Then you cannot directly cast it to a long but must first unpack it as an int:
var myLong = (long)(int)rdr.GetValue(0);
This will be quite tricky using generics, I would say. Well, you could make generic methods with two type arguments; one specifying what type the field is, and one specifying the type you want. But I don't really see the need; SqlDataReader already has methods for the various data types, such as GetInt32, GetInt64 and so on, so the generic method would not really give any added value in that case.

Categories