linq-to-sql SingleOrDefault return when null - c#

I'm writing a linq-to-sql query and I'm loading an ID (a bigint in the database and a long in my code) from a table, something like this:
var SomeQuery = (from x in ...
select x.ID).SingleOrDefault();
When I get the result, I use SingleOrDefault in case the return is empty. Does that mean that if the result is empty the SomeQuery variable will be 0 or null?
Thanks.

If you look the documenation for SingleOrDefault
Returns the only element of a sequence, or a default value if the
sequence is empty; this method throws an exception if there is more
than one element in the sequence.
It cleary states that if the sequence is empty it will return the default value which for long and bigint is 0. Why explained below
Documenation for default keyword states
In generic classes and methods, one issue that arises is how to assign
a default value to a parameterized type T when you do not know the
following in advance:
Whether T will be a reference type or a value type.
If T is a value type, whether it will be a numeric value or a struct.
Given a variable t of a parameterized type T, the statement t = null
is only valid if T is a reference type and t = 0 will only work for
numeric value types but not for structs. The solution is to use the
default keyword, which will return null for reference types and zero
for numeric value types.

Default is returned if no element found.(default value of int is 0)
Value is returned if one is found.
Exception is thrown if more than one is found.

Related

What is the "default value" returned by the Enumerable.SingleOrDefault method?

I wrote this piece of code to look for one 'Vendedor' (Salesman) that satisfies the condition of having the same 'codigo' (id) entered in a TextBox by a user:
using (TccContext context = new TccContext())
{
Vendedor[] query = (from vendedor in context.Vendedores
where vendedor.codigo == Convert.ToInt64(this.textBoxProcurarCodFuncionario.Text)
select vendedor).ToArray();
if (query.Length == 1)
{
textBoxCodigo.Text = query[0].codigo.ToString();
textBoxNome.Text = query[0].nome;
textBoxTotalVendaMensal.Text = query[0].totalVendaMensal.ToString();
}
else
{
MessageBox.Show("Código não encontrado,\n tente novamente...",
"Atualizar Funcionário",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
this.Limpar();
}
}
I'd like to replace the ToArray method for SingleOrDefault, but I got stuck with:
Returns the only element of a sequence, or a default value if the
sequence is empty; this method throws an exception if there is more
than one element in the sequence.
In this case what would be a "default value" as said in the documentation, I'd like to be able to treat this "exception", but I don't know what it is?
Can someone explain me what would be this "default value"? I just started using Entity Framework so don't take too hard with me.
Thanks in advance.
What is returned is default(T), which means null for reference types and 'zero' value for value types.
default(T) will return null for reference types and zero for numeric value types. For structs, it will return each member of the struct initialized to zero or null depending on whether they are value or reference types. For nullable value types, default returns a System.Nullable<T>, which is initialized like any struct.
For nullable types default will be null.
For integer its 0, and I think all other numbers are as well. I'll see if I can find the docs...
"The default value for reference and nullable types is null."
http://msdn.microsoft.com/en-us/library/bb342451.aspx
The default value for nullable types and reference types (This would be your Vendor class) is null.
For default values of the other types, you can look at this default value table. It is usually 0, even for enums; this can be problematic if you manually specified the values in your enum.
For nullable types it is null and for integers it is 0
From here:-
The default value for reference and nullable types is nullptr.
The SingleOrDefault method does not provide a way to specify a default
value. If you want to specify a default value other than
default(TSource), use the
DefaultIfEmpty(IEnumerable, TSource)

nullable object must have a value in Linq

I use following Linq To Entitiy To get the first and only record of my 'siteconfig' Entity :
var site = unitofwork.SiteConfigRepository.Get().FirstOrDefault();
But when my application comes to the following code, throws 'nullable object must have a value' :
if (site!= null) { TimeSpan span = DateTime.Now.Subtract((DateTime)site.logindDate ); }
And the only nullable type in my entity is a property called logindDate and is of type DateTime.
Any one help me out?
Try something like this:
if (site!= null)
{
if (site.loginDate.HasValue)
{ TimeSpan span = DateTime.Now.Subtract((DateTime)site.logindDate.Value ); }
}
You are not checking for a null loginDate and I suspect that may be the problem. Remember, when you have a nullable type, you need to check for HasValue, and then get the value from the Value property.
IEnumerable.FirstOrDefault() returns the first element of the enumerable, or default(T) (which is generally null, unless T is a value type) if there is no element in the list. Most probably your Get() returns an empty enumerable.
On a related matter (if indeed it is what happens), if you're sure that there is always one and only one element returned by a list, you should use Single() (because then you will have an exception thrown at that line) or test it against null just after the FirstOrDefault(). I think it's best having exceptions throwing or handling at the source of the unexpected behavior, and not several lines later.

C# null - is it an object

When I was writing C# code a few days ago I noticed that the compiler complained that I had to cast null to a specific object.
Does this mean that null is simply an uninstantiated version of the type? Or is it a singleton value of a Null class like Java (even though it has special privileges)?
EDIT: an example of the code giving the error would be:
public String duplicate(String toDuplicate)
{
return toDuplicate + toDuplicate;
}
public String duplicate(int? toDuplicate)
{
String asString = toDuplicate.toString();
return asString + asString;
}
public static int Main(string[] args)
{
//This needs to be cast:
duplicate(null);
//To:
duplicate((string)null);
}
The reason I commented on null in Java was after reading this:
There is also a special null type, the
type of the expression null, which has
no name. Because the null type has no
name, it is impossible to declare a
variable of the null type or to cast
to the null type. The null reference
is the only possible value of an
expression of null type. The null
reference can always be cast to any
reference type. In practice, the
programmer can ignore the null type
and just pretend that null is merely a
special literal that can be of any
reference type.
Found here: Is null an Object?
I get the error you refer when i have overloaded methods and the compiler can't resolve which method to call at compile time. Is that it?
According to the MSDN description:
The null keyword is a literal that represents a null reference, one that does not refer to any object. null is the default value of reference-type variables. Ordinary value types cannot be null. However, C# 2.0 introduced nullable value types.
null is the "uninstanciated reference" for any type. It is not a value. null has no defined type.
No - the null is just a literal for the null reference.
The reason you need to "cast" it in this way (I put the word cast in quotes because you are not really casting an instance of anything), is purely to help the compiler resolve which overload of a method you are calling, or the method you are calling even exists.
In your example, you need to specify that you are calling the method "duplicate" that takes a single string argument. If you omit the cast, then the compiler only knows that the method you intended to call is called "duplicate" and has a single argument, but can't tell what type the argument is - did you mean to call duplicate(string) or did you mean to call duplicate(some other type)? Should it compile, or should it error telling you the method you are trying to call does not exist?
You will also get the same issue if you had a duplicate(byte[]) defined, because now your call is ambiguous without the explicit cast.
No its not an object. null is the default value of reference-type variables. Ordinary value types cannot be null. but there is another set called nullable types.
You are probably referring to the fact that the following leads to a compiler error:
int? nullableInt = (somecondition) ? value : null;
Indeed you need to add a cast here:
int? nullableInt = (somecondition) ? value : (int?)null;
Even though I'm not able to explain this in detail, I'd suspect the following:
int? is actually a short form for Nullable<int>, so it is basically an object instance. When assigning an int value to nullableInt, a property of Nullable<int> will be set internally. Directly assigning null would also be ok.
The conditional assignment however, would return two different types: int in case somecondition is true and object (null) otherwise.
Now the compiler doesn't know how to handle this, as the ternary operator needs to return values of the same type. So you need to specify the desired "type for the null value".
Sorry if this is not a very deep technical explanation - I'm sure there's somebody who can elaborate this better, but it might help understand this better.

Why can't I use the as keyword for a struct?

I defined the following struct:
public struct Call
{
public SourceFile caller;
public SourceFile callee;
public Call(SourceFile caller, SourceFile callee)
{
this.caller = caller;
this.callee = callee;
}
}
Later, I assign it to the Tag property of another object:
line.Tag = new Call(sf1, sf2);
But when I try to retrieve the Tag property like so,
Call call = line.Tag as Call;
Visual Studio gives the following compile-time error:
The operator as must be used within a
reference type or nullable type
What is the meaning of that? And how can I solve it?
Some of the existing answers aren't quite right. You can't use non-nullable types with as, because the result of as is the null value of the type if the first operand isn't actually of an appropriate type.
However, you can use as with value types... if they're nullable:
int a = 10;
object o = a;
int? x = o as int?; // x is a Nullable<int> with value 10
long? y = o as long?; // y is a Nullable<long> with the null value
So you could use:
Call? call = line.Tag as Call?;
Then you can use it as:
if (call != null)
{
// Do stuff with call.Value
}
Two caveats though:
In my experience this is slower than just using is followed by a cast
You should seriously reconsider your current Call type:
It's exposing public fields, which is generally poor encapsulation
It's a mutable value type, which is almost certainly a mistake
I would strongly suggest you make it a class instead - at which point this problem goes away anyway.
Another thought: if the tag should always be a Call, then it's better to cast it:
Call call = (Call) line.Tag;
That way, if the data doesn't match your expectation (i.e. there's some bug such that the Tag isn't a Call) then you get to find out about it early, rather than after you've potentially done some other work. Note that this cast will behave differently depending on whether Call is a struct or a class, if Tag is null - you can cast a null value to a variable of a reference type (or a nullable value type), but not to a non-nullable value type.
A struct is a value type, so it cannot be used with the as operator. The as operator must be able to assign a value of null if the cast fails. This is only possible with a reference type or a nullable value type.
There are a couple ways to solve this, but your best bet is to change your Call type from a struct to a class. This will essentially change your type from a value type to a reference type, which allows the as operator to assign a value of null if the cast fails.
For more information on value types vs. reference types, this is a decent article. Also, have a look on MSDN:
value types
reference types
as-operator
nullable types.
From the C# Spec
§7.10.11 The as operator is used to
explicitly convert a value to a given
reference type or nullable type. Unlike a cast expression
(§7.7.6), the as operator never throws
an exception. Instead, if the
indicated conversion is not possible,
the resulting value is null.
References and nullable types can be null. Stucts are value types so they can't be null.
Call? call = line.Tag as Call?;
It's a limitation of C#. If the type were a reference type, then if the cast failed it would simply return 'null', but since it's a value type, it doesn't know what to return when the cast fails.
You must replace your use of as with two: 'is' and 'as'
if (line.Tag is Call) {
call = (Call)line.Tag;
} else {
// Do whatever you would do if as returned null.
}
What is the meaning - As stated, structures are value types.
How can I solve it - Change it to
Call call = line.Tag;

What is the best way to deal with DBNull's

I frequently have problems dealing with DataRows returned from SqlDataAdapters. When I try to fill in an object using code like this:
DataRow row = ds.Tables[0].Rows[0];
string value = (string)row;
What is the best way to deal with DBNull's in this type of situation.
Nullable types are good, but only for types that are not nullable to begin with.
To make a type "nullable" append a question mark to the type, for example:
int? value = 5;
I would also recommend using the "as" keyword instead of casting. You can only use the "as" keyword on nullable types, so make sure you're casting things that are already nullable (like strings) or you use nullable types as mentioned above. The reasoning for this is
If a type is nullable, the "as" keyword returns null if a value is DBNull.
It's ever-so-slightly faster than casting though only in certain cases. This on its own is never a good enough reason to use as, but coupled with the reason above it's useful.
I'd recommend doing something like this
DataRow row = ds.Tables[0].Rows[0];
string value = row as string;
In the case above, if row comes back as DBNull, then value will become null instead of throwing an exception. Be aware that if your DB query changes the columns/types being returned, using as will cause your code to silently fail and make values simple null instead of throwing the appropriate exception when incorrect data is returned so it is recommended that you have tests in place to validate your queries in other ways to ensure data integrity as your codebase evolves.
If you aren't using nullable types, the best thing to do is check to see if the column's value is DBNull. If it is DBNull, then set your reference to what you use for null/empty for the corresponding datatype.
DataRow row = ds.Tables[0].Rows[0];
string value;
if (row["fooColumn"] == DBNull.Value)
{
value = string.Empty;
}
else
{
value = Convert.ToString(row["fooColumn"]);
}
As Manu said, you can create a convert class with an overloaded convert method per type so you don't have to pepper your code with if/else blocks.
I will however stress that nullable types is the better route to go if you can use them. The reasoning is that with non-nullable types, you are going to have to resort to "magic numbers" to represent null. For example, if you are mapping a column to an int variable, how are you going to represent DBNull? Often you can't use 0 because 0 has a valid meaning in most programs. Often I see people map DBNull to int.MinValue, but that could potentially be problematic too. My best advice is this:
For columns that can be null in the database, use nullable types.
For columns that cannot be null in the database, use regular types.
Nullable types were made to solve this problem. That being said, if you are on an older version of the framework or work for someone who doesn't grok nullable types, the code example will do the trick.
Add a reference to System.Data.DataSetExtensions, that adds Linq support for querying data tables.
This would be something like:
string value = (
from row in ds.Tables[0].Rows
select row.Field<string>(0) ).FirstOrDefault();
I always found it clear, concise, and problem free using a version of the If/Else check, only with the ternary operator. Keeps everything on one row, including assigning a default value if the column is null.
So, assuming a nullable Int32 column named "MyCol", where we want to return -99 if the column is null, but return the integer value if the column is not null:
return row["MyCol"] == DBNull.Value ? -99 : Convert.ToInt32(Row["MyCol"]);
It is the same method as the If/Else winner above - But I've found if you're reading multiple columns in from a datareader, it's a real bonus having all the column-read lines one under another, lined up, as it's easier to spot errors:
Object.ID = DataReader["ID"] == DBNull.Value ? -99 : Convert.ToInt32(DataReader["ID"]);
Object.Name = DataReader["Name"] == DBNull.Value ? "None" : Convert.ToString(DataReader["Name"]);
Object.Price = DataReader["Price"] == DBNull.Value ? 0.0 : Convert.ToFloat(DataReader["Price"]);
If you have control of the query that is returning the results, you can use ISNULL() to return non-null values like this:
SELECT
ISNULL(name,'') AS name
,ISNULL(age, 0) AS age
FROM
names
If your situation can tolerate these magic values to substitute for NULL, taking this approach can fix the issue through your entire app without cluttering your code.
DBNull implements .ToString() like everything else. No need to do anything. Instead of the hard cast, call the object's .ToString() method.
DataRow row = ds.Tables[0].Rows[0];
string value;
if (row["fooColumn"] == DBNull.Value)
{
value = string.Empty;
}
else
{
value = Convert.ToString(row["fooColumn"]);
}
this becomes:
DataRow row = ds.Tables[0].Rows[0];
string value = row.ToString()
DBNull.ToString() returns string.Empty
I would imagine this is the best practice you're looking for
It is worth mentioning, that DBNull.Value.ToString() equals String.Empty
You can use this to your advantage:
DataRow row = ds.Tables[0].Rows[0];
string value = row["name"].ToString();
However, that only works for Strings, for everything else I would use the linq way or a extension method. For myself, I have written a little extension method that checks for DBNull and even does the casting via Convert.ChangeType(...)
int value = row.GetValueOrDefault<int>("count");
int value = row.GetValueOrDefault<int>("count", 15);
Often when working with DataTables you have to deal with this cases, where the row field can be either null or DBNull, normally I deal with that like this:
string myValue = (myDataTable.Rows[i]["MyDbNullableField"] as string) ?? string.Empty;
The 'as' operator returns null for invalid cast's, like DBNull to string, and the '??' returns
the term to the right of the expression if the first is null.
You can also test with Convert.IsDBNull (MSDN).
I usually write my own ConvertDBNull class that wraps the built-in Convert class. If the value is DBNull it will return null if its a reference type or the default value if its a value type.
Example:
- ConvertDBNull.ToInt64(object obj) returns Convert.ToInt64(obj) unless obj is DBNull in which case it will return 0.
For some reason I've had problems with doing a check against DBNull.Value, so I've done things slightly different and leveraged a property within the DataRow object:
if (row.IsNull["fooColumn"])
{
value = string.Empty();
}
{
else
{
value = row["fooColumn"].ToString;
}
Brad Abrams posted something related just a couple of days ago
http://blogs.msdn.com/brada/archive/2009/02/09/framework-design-guidelines-system-dbnull.aspx
In Summary "AVOID using System.DBNull. Prefer Nullable instead."
And here is my two cents (of untested code :) )
// Or if (row["fooColumn"] == DBNull.Value)
if (row.IsNull["fooColumn"])
{
// use a null for strings and a Nullable for value types
// if it is a value type and null is invalid throw a
// InvalidOperationException here with some descriptive text.
// or dont check for null at all and let the cast exception below bubble
value = null;
}
else
{
// do a direct cast here. dont use "as", "convert", "parse" or "tostring"
// as all of these will swallow the case where is the incorect type.
// (Unless it is a string in the DB and really do want to convert it)
value = (string)row["fooColumn"];
}
And one question... Any reason you are not using an ORM?
You should also look at the extension methods. Here are some examples to deal with this scenerio.
Recommended read
If you are concerned with getting DBNull when expecting strings, one option is to convert all the DBNull values in the DataTable into empty string.
It is quite simple to do it but it would add some overhead especially if you are dealing with large DataTables. Check this link that shows how to do it if you are interested

Categories

Resources