How do I make a lambda query nullable? - c#

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.

Related

What is the equivalent LINQ to SQL query expression of this SQL statement?

SQL query run OK:
select o.OpName,isnull(Amount,0) from Setup_tblOperator o
left join
(
select t.opid,sum(isnull(t.Amount,0)) Amount from
Load_tblTransaction t
where cast(t.RequestTime as date)='2017-04-24'
group by t.opid
) t on t.OpId=o.OpId
where o.IsActive=1
I tried following code in LINQ to SQL:
var trans = (from o in mouDataEntities.Setup_tblOperator
join t in mouDataEntities.Load_tblTransaction
on o.OpId equals t.OpId into ot
from n in ot.Where(
t => DbFunctions.TruncateTime(t.RequestTime) ==
DbFunctions.TruncateTime(seldate))
.DefaultIfEmpty()
select new
{
Operator = o.OpName,
Amount= n.Amount
});
var gt = trans.GroupBy(t => t.Operator)
.Select(n => new { Operator = n.Key, Amount = n.Sum(a=>a.Amount) })
.ToList();
It throws an 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.
There are a few cases where the straightforward SQL to C# translation gets accepted, but fails at run-time. In C#, set.DefaultIfEmpty().Select(n => n.Amount), where n.Amount has type int, would have a result type IEnumerable<int>. It would fail with a NullReferenceException if set were empty, because in that case n would become null as well. Therefore, there is no reason why you'd need int?, since you can't ever get null as a result.
In SQL, it's not so easy. Retrieving a column of the default row introduced by LEFT JOIN is valid, and produces NULL.
But the C# code is expecting a value of type int, and an int can't be null.
You need to find some way to trick the type system so that you can specify how null should be handled. A simple cast suffices:
Change
Amount = n.Amount
to
Amount = (int?) n.Amount
Or, to turn null into 0,
Amount = (int?) n.Amount ?? 0

Ternary operator in lambda expression 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.

MVC linq to sql sum

Trying to get the values returned from a database based on the sum of a field.
But getting this message:
The cast to value type 'System.Decimal' failed because the
materialized value is null. Either the result type's generic parameter
or the query must use a nullable type.
It is valid for the database to contain no records for that user for that day, hence I went down the nullable route. In the good old days I would have built a Stored Procedure with `ISNULL` in it!!!
This is the basic expression I have:
decimal? foodCount = dbContext.fad_userFoods.Where(uf => uf.dateAdded == thisDate && uf.userID == thisGuid).Sum(uf=>(decimal?)uf.quantityAmount ?? 0m);
Googling it came up with the nullable definitions and use of the ?? with the "m" as it's decimal. But still the error persists!
Your collective help will be invaluable as ever. Thanks in advance.
Use the DefaultIfEmpty method. This will fill in a 0 if no value at all can be found.
decimal foodCount = dbContext.fad_userFoods
.Where(uf => uf.dateAdded == thisDate && uf.userID == thisGuid)
.Select(uf => uf.quantityAmount)
.DefaultIfEmpty()
.Sum();
Since it's a sum and not average you don't really mind null-values?
Why not simply removing the null-values?
decimal? foodCount = dbContext.fad_userFoods
.Where(uf =>
uf.dateAdded == thisDate &&
uf.userID == thisGuid &&
uf.quantityAmount != null)
.Sum(uf=> uf.quantityAmount);
Use Convert.ToDecimal(), this will handle your null issue.
decimal foodCount = dbContext.fad_userFoods.Where(uf => uf.dateAdded == thisDate
&& uf.userID == thisGuid)
.Sum(uf=> Convert.ToDecimal(uf.quantityAmount ?? 0m));
LINQ to Entities does not recognize the method 'System.Decimal
ToDecimal(System.Decimal)' method, and this method cannot be
translated into a store expression.
Edit:
decimal foodCount = dbContext.fad_userFoods.Where(uf => uf.dateAdded == thisDate
&& uf.userID == thisGuid)
.Sum(uf=> { decimal result;
decimal.TryParse(uf.quantityAmount,out result);
return result;});
The confusion originates from the fact the Sum in LINQ To Entities is processed a bit different than in LINQ To Objects. Although from declaration it looks like that calling it on a let say decimal will return 0, when the target set is empty actually the SQL SUM function returns NULL, even if the target column is not nullable.
Once you know that, there are two ways of resolving it.
Let say we have a table with decimal column and the original expression is
table.Sum(item => item.Column)
First way is to convert it using the pattern contained in the Maarten answer:
table.Select(item => item.Column).DefaultIfEmpty().Sum()
The second way is to explicitly convert the non nullable type to nullable inside the function and then apply null-coalescing operator to the result:
table.Sum(item => (decimal?)item.Column) ?? 0
Both ways work and produce one and the same result, so use the one that better suits your personal preferences.
For completeness, applying the second approach in your case would be to basically move the ?? 0 outside of the Sum call:
decimal foodCount = dbContext.fad_userFoods
.Where(uf => uf.dateAdded == thisDate && uf.userID == thisGuid)
.Sum(uf => (decimal?)uf.quantityAmount) ?? 0;

If Linq query is Null return System.Int32.MinValue

I am trying to do a LINQ query on a field to determine the highest number than add one to it. However, if there is nothing in the table it is crashing on me. I have tried two separate ways to fix this problem:
int? tn = db.Tickets.Max(t => t.TicketNumber);
if (tn == null)
{
ticket.TicketNumber = db.Tickets.Max(t => t.TicketNumber) + 1;
}
else
{
ticket.TicketNumber = System.Int32.MinValue + 1;
}
and
ticket.TicketNumber = db.Tickets.Max(t => t.TicketNumber) + 1 ?? System.Int32.MinValue + 1;
I have tried a few other ways but they all are minor changes to these two methods. The error that I received on the former one is:
Either the result type's generic parameter or the query must use a nullable type.
What am I missing?
You can't add 1 and null. Try:
ticket.TicketNumber = (db.Tickets.Max(t => t.TicketNumber) ?? Int32.MinValue) + 1;
UPDATE
You can only use ?? when there's a nullable involved. It appears here that you're always going to get some value back other than null. You might try something like:
var maxTicketNumber = db.Tickets.Max(t => t.TicketNumber);
ticket.TicketNumber = maxTicketNumber == default(int) ? Int32.MinValue : maxTicketNumber;
That just compares your number from the database with the default for an int if no real value is provided (0). That's essentially what you would get rather than null, since the property is not nullable. However, 0 may be a perfectly valid value, in which case you wouldn't want to use this code. It really depends on what you're actually trying to achieve. Perhaps if you provide more information in your question, we'll be able to assist you better.
How about
ticket.TicketNumber = db.Tickets.Max(t => (int?)t.TicketNumber).GetValueOrDefault(int.MinValue) + 1;
Note the int? cast, if you don't put it you'll get the same exception if the table does not contain records. Btw, the full exception message is
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.
int? tn = db.Tickets.Max(t => (int?) t.TicketNumber).GetValueOrDefault(int.MinValue) + 1;
^^^^^^
The Enumerable.Max(IEnumerable<int>) overload doesn't allow for empty enumerables because it returns int, which cannot hold null. The Enumerable.Max(IEnumerable<int?>) overload does allow for empty enumerables.
Note that it's pretty uncommon to start with int.MinValue + 1 -- did you perhaps want 0 instead of int.MinValue?
You can use DefaultIfEmpty, you just need to select the TicketNumber before:
ticket.TicketNumber = db.Tickets
.Select(t => t.TicketNumber)
.DefaultIfEmpty(Int32.MinValue)
.Max() + 1;
The use of DefaultIfEmpty with a custom fallback value prevents an exception at Enumerable.Max because the sequence is never empty.
If you are using Entity Framework as your back end, this Linq statement (although it looks like a sledgehammer on a nut) should translate to a reasonably efficient SQL query:
ticket.TicketNumber = db.Tickets.OrderByDescending(t => t.TicketNumber).FirstOrDefault() + 1;
The use of FirstOrDefault means that you actually get zero when there are no existing entries (your TicketNumber field is non-nullable, and its default is 0), but as I said in the comments, that means that your first ticket number is 1, which seems like a more realistic value that int.MinValue + 1.

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.

Categories

Resources