Ternary operator in lambda expression C# - c#

I am trying to put a conditional expression with in a lambda query as below
GetPeers(bool? isConnected = true)
{
dbContext
.peers
.Where(m => isConnected.HasValue ? m.IsConnected == isConnected.Value : true)
.ToList();
}
Above statement gives me Nullable object must have a value. exception.
I dont get it! What is wrong in my query?
What I want if isConnected is null, then it should be returning all the records otherwise on the basis of m.IsConnected == isConnected.Value,

This is an issue with how Entity Framework is translating the ternary expression, it is attempting to create a SQL parameter using the result of isConnected.Value but isConnected is null so it throws.
My preferred option is to only apply the predicate if there is actually a predicate to apply:
IQueryable<Peer> peers = dbContext.peers;
if(isConnected.HasValue)
{
var isConnectedValue = isConnected.Value;
peers = peers.Where(m => m.IsConnected == isConnectedValue);
}
return peers.ToList();

You can change this
m.IsConnected == isConnected.Value
to this
m.IsConnected == (isConnected.HasValue && isConnected.Value)
The problem is that isConnected doesn't have always a value. It's a bool?. So it can has a value or not (null). If it has a value, it would be either true/false. The problem arises, when it has no value. This is happening due to conditional operator. According to the documentation:
The conditional operator (?:) returns one of two values depending on
the value of a Boolean expression. Following is the syntax for the
conditional operator.
condition ? first_expression : second_expression;
Either the type of first_expression and second_expression must be the
same, or an implicit conversion must exist from one type to the other.
For the full documentation, please have a look here.

Related

Operator '??' cannot be applied to operands of type 'System.Guid?' and 'string'

I am getting this error in a LINQ query with the below code:
"Operator '??' cannot be applied to operands of type 'System.Guid?' and 'string'"
I have a nullable GUID object, here I am checking if the GUID Object is null, then I need to return String.Empty else will be converting GUID to string
List<Report> queryresult =
reportDatatable.AsEnumerable()
.Where(c => c.Field<Guid?>("ParentID") == Guid.Parse("XXXXXX-XXX-XXXXX-XXXXX-XXX))
.Select(c=> new Report()
{
ID = (c.Field<Guid?>("ID") ?? String.Empty).ToString(), //error here
...
}).ToList();
Below link as simplest way to check whether object is null or not.
Suggest if any other approach to check GUID object is null or not
Edit:
Apparently, what suits your need best would be this:
ID = (c.Field<Guid?>("ID") ?? Guid.Empty) == Guid.Empty ? String.Empty : c.Field<Guid?>("ID").ToString(), //try this
Original
Convert your GUID to string first:
c.Field<Guid?>("ID").ToString() ?? String.Empty
Then it should be ok.
Else, use Guid.Empty instead of String.Empty the idea here is that both sides in ?? must match. Like comparing Apple to Apple
To prevent c.Field<Guid?>("ID") == null being executed, in C#6, you could make it more simply like this
c.Field<Guid?>("ID")?.ToString() ?? String.Empty
Given that Nullable<>'s ToString() override produces an empty string if the value is null, you can simply write
ID = c.Field<Guid?>("ID").ToString()
Depending on your reporting code, better yet could be to make Report's ID of type Guid?, but that won't necessarily always work.
As you have nullable GUID, you can use HasValue to check if value exist
(c.Field<Guid?>("ID").HasValue ? c.Field<Guid?>("ID").Value:String.Empty).ToString()
You need to return Guid.Empty instead of String.Empty for ?? operator as left hand side is Guid not string. That is what the compiler error "Operator '??' cannot be applied to operands of type 'System.Guid?' and 'string'" suggests.
ID = (c.Field<Guid?>("ID") ?? Guid.Empty).ToString(),
Edit
If you want empty string then you can put condition to return empty string for Guid.Empty. Your query will end up with something like this.
ID = (c.Field<Guid?>("ID") ?? Guid.Empty) == Guid.Empty ?
String.Empty : c.Field<Guid?>("ID").ToString(),

How do I make a lambda query nullable?

I am getting the following error:
The cast to value type 'System.Int32' failed because the materialized
value is null. Either the result type's generic parameter or the query
must use a nullable type.
How do I make my lambda expression nullable ?
d.QtyOnOrder = db.DieOrders.Where(c=>c.DrawDie.SizeUS==d.SizeUS).Sum(c => c.QtyOpen);
Update: The code below works. Can someone tell me why the Linq expression works and the Lambda does not ?
var dies = from e in db.DieOrders
where e.DrawDieID == d.ID && e.QtyOpen !=null
select e;
var _qtyOpen = dies.Sum(x => x.QtyOpen);
I like #RezaRahmati's suggestion, but an alternative is:
d.QtyOnOrder = db.DieOrders.Where(c=>c.DrawDie.SizeUS==d.SizeUS && d.QtyOpen.HasValue)
.Sum(c => c.QtyOpen);
If all of the QtyOpen are null, then you are summing an empty list which will give you zero.
What I like about Reza's answer however, is that it makes it more explicit that you will set the result to zero if the sum is null.
I think the problem is QtyOnOrder, since Sum can returns null QtyOnOrder should be nullable or use this syntax:
d.QtyOnOrder = db.DieOrders.Where(c=>c.DrawDie.SizeUS==d.SizeUS).Sum(c => c.QtyOpen) ?? 0;
I needed to cast as well, for example the following;
d.QtyOnOrder = db.DieOrders.Where(c=>c.DrawDie.SizeUS==d.SizeUS)
.Sum(c => (int?)c.QtyOpen) ?? 0;
The error indicates that d.QtyOnOrder is not nullable so the solution is to change the class definition so that it is an int? (short hand for Nullable<int>) or to use the null coalescing operator on the left hand side to ensure that null is never returned;
db.DieOrders.Where(c=>c.DrawDie.SizeUS==d.SizeUS).Sum(c => c.QtyOpen) ?? 0;
If the datatype of "QtyOnOrder" is int, You should make it as int?. So now even if sum returns null, code do not generate any error.
int? is a nullable datatype. To know about Nullable types Visit Nullable Types.

What is the proper AND operator in SQLite where statement

Using & or && in the where-statement? It seems it is not working.
can anyone help me with the Lambda expression on Sqlite query statement.
Thanks.
var existingItemUoM = db2.Table().Where(c => c.UoM == ItemNo & c.ItemNo == CodeforUoM).SingleOrDefault()
Since you seem to be using linq, the correct operator for AND is
&&
A good reference here are the 101 LINQ Samples.
The single & is a non-short-circuit and-operator. This means even if the first condition evaluates to true, the second condition will be checked (which isn't the case when using &&, the short-circuit and-operator).
Furthermore, in a real SQLite statement the correct expression for the boolean and-operator would be and, refer to the expressions of SQLite.
Correct operator for AND is &&, check with following where class
var existingItemUoM = db2.Table().Where((c => c.UoM) && (c.UoM == ItemNo) && (c.ItemNo == CodeforUoM)).SingleOrDefault()

Linq to objects when object is null VS Linq to SQL

I have this Linq to object query:
var result = Users.Where(u => u.Address.Country.Code == 12)
I get an exception if the Address or the Country are null.
Why this query doesn't check if the address is null and just after that procced?
This way I won't need to write this terrible query:
var result = Users.Where(u => u.Address != null &&
u.Address.Country != null &&
u.Address.Country.Code == 12)
In Linq to SQL the first query wiil do the job(from other reasons of course).
Is the a way to avoid the "null checks" in linq to object?
Unfortunately, "null" is treated inconsistently in C# (and in many other programming languages). Nullable arithmetic is lifted. That is, if you do arithmetic on nullable integers, and none of the operands are null, then you get the normal answer, but if any of them are null, you get null. But the "member access" operator is not lifted; if you give a null operand to the member access "." operator, it throws an exception rather than returning a null value.
Were we designing a type system from scratch, we might say that all types are nullable, and that any expression that contains a null operand produces a null result regardless of the types of the operands. So calling a method with a null receiver or a null argument would produce a null result. That system makes a whole lot of sense, but obviously it is far too late for us to implement that now; millions upon millions of lines of code have been written that expects the current behaviour.
We have considered adding a "lifted" member access operator, perhaps notated .?. So you could then say where user.?Address.?Country.?Code == 12 and that would produce a nullable int that could then be compared to 12 as nullable ints normally are. However, this has never gotten past the "yeah, that might be nice in a future version" stage of the design process so I would not expect it any time soon.
UPDATE: The "Elvis" operator mentioned above was implemented in C# 6.0.
No, it is a null reference exception just like accessing var x = u.Address.Country.Code; would be a NullReferenceException.
You must always make sure what you are de-referencing is not null in LINQ to objects, as you would with any other code statements.
You can do this either using the && logic you have, or you could chain Where clauses as well (though this would contain more iterators and probably perform slower):
var result = Users.Where(u => u.Address != null)
.Where(u.Address.Country != null)
.Where(u.Address.Country.Code == 12);
I've seen some Maybe() extension methods written that let you do the sort of thing you want. Some people do/don't like these because they are extension methods that operate on a null reference. I'm not saying that's good or bad, just that some people feel that violates good OO-like behavior.
For example, you could create an extension method like:
public static class ObjectExtensions
{
// returns default if LHS is null
public static TResult Maybe<TInput, TResult>(this TInput value, Func<TInput, TResult> evaluator)
where TInput : class
{
return (value != null) ? evaluator(value) : default(TResult);
}
// returns specified value if LHS is null
public static TResult Maybe<TInput, TResult>(this TInput value, Func<TInput, TResult> evaluator, TResult failureValue)
where TInput : class
{
return (value != null) ? evaluator(value) : failureValue;
}
}
And then do:
var result = Users.Where(u => u.Maybe(x => x.Address)
.Maybe(x => x.Country)
.Maybe(x => x.Code) == 12);
Essentially, this just cascades the null down the chain (or default value in the case of a non-reference type).
UPDATE:
If you'd like to supply a non-default failure value (say Code is -1 if any part is null), you'd just pass the new failure value into Maybe():
// if you wanted to compare to zero, for example, but didn't want null
// to translate to zero, change the default in the final maybe to -1
var result = Users.Where(u => u.Maybe(x => x.Address)
.Maybe(x => x.Country)
.Maybe(x => x.Code, -1) == 0);
Like I said, this is just one of many solutions. Some people don't like being able to call extension methods from null reference types, but it is an option that some people tend to use to get around these null cascading issues.
Currently, however, there is not a null-safe de-reference operator built into C#, so you either live with the conditional null checks like you had before, chain your Where() statements so that they will filter out the null, or build something to let you cascade the null like the Maybe() methods above.

c# .net 4.0 : nullable input string parameter and the lambda expressions

I have a following method:
public IQueryable<Profile> FindAllProfiles(string CountryFrom, string CountryLoc)
{
return db.Profiles.Where(p => p.CountryFrom.CountryName.Equals(CountryFrom,StringComparison.OrdinalIgnoreCase));
}
Right now, it just filters by CountryFrom but I need to filter it by CountryLoc as well.
So how do I modify the Where filter?
Also, CountryFrom could be null or CountryLoc could be null. So how do I modify the method's signature to all the nullable input string parameter.
I know how to do this in SQL but I am not sure about lambda expressions or LINQ.
Thanks
Your question isn't actually LINQ-specific. You can put any boolean conditions inside the lambda that you want, such as:
p => p.CountryFrom.CountryName.Equals(...) && p.CountryLoc.CountryName.Equals(...)
To handle null values you can use the static string.Equals method instead, like this:
p => string.Equals(p.CountryFrom.CountryName, CountryName, StringComparison.OrdinalIgnoreCase)
If this starts getting too long you could always extract it into a method.
return db.Profiles
.Where(p => p.CountryFrom.CountryName.Equals(CountryFrom,
StringComparison.Ordinal.IgnoreCase) &&
p.CountryLoc.CountryName.Equals(CountryLoc,
StringComparison.Ordinal.IgnoreCase));
Sorry...there was no way to make that statement pretty.
Just remember you can use any boolean logic you'd like inside of the Where extension method. It's just as easy as it would be anywhere else.
Also, a string parameter can be null no matter what (it's a reference type) so you don't need to worry about making things nullable.
You'll want to use the logical and operator "&&" in your lambda expression to filter by both CountryFrom and CountryLoc. Ex
db.Profiles.Where(p => p.CountryFrom == CountryFrom && p.CountryLoc == CountryLoc);
In C# strings are reference types and therefore can be null. You can check for null values using
myString == null

Categories

Resources