Linq 2 SQL Sum using lambda and handling nulls - linq

When using sum with lambda in Linq to SQL using the following code:
int query = (from f in odc.RDetails
where f.ticketID == int.Parse(ticket.ToString())
select f).Sum(x => x.Rate);
I get the following error:
The null value cannot be assigned to a member with type System.Int32 which is a non-nullable value type.

. You have to make sure x.Rate is an int, and not an int? (an int that accepts null as a value).
. If the query has no elements, .Sum won't do anything and will return null. Choose a default value, let's say 0.
var query = from f in odc.RDetails
where f.ticketID == int.Parse(ticket.ToString())
select f;
int result = query.Any()
? query.Sum(x => x.Rate ?? 0) // use the ?? if x.Rate is an "int?".
: 0; // default value you can choose.

I would break the int.Parse(ticket.ToString()) onto its own line to isolate that parse from the Linq for debugging.
We don't know whether that is throwing the exception or if one of the RDetails.Rate values is null. Is it indeed a Nullable<int>?
If RDetails.Rate is a Nullable<int>, then you could ...Sum(x => x.Rate ?? 0) and avoid the exception.

Related

Unable to create a constant value - only primitive types or Enumeration types allowed

I have seen some questions related to this Exception here but none made me understand the root cause of the problem. So here we have one more...
var testquery =
((from le in context.LoanEMIs.Include("LoanPmnt")
join lp in context.LoanPmnts on le.Id equals lp.LoanEMIId
where lp.PmntDtTm < date && lp.IsPaid == false
&& le.IsActive == true && lp.Amount > 0
select new ObjGetAllPendingPmntDetails
{
Id = lp.Id,
Table = "LoanEMI",
loanEMIId = lp.LoanEMIId,
Name = le.AcHead,
Ref = SqlFunctions.StringConvert((double)le.FreqId),
PmntDtTm = lp.PmntDtTm,
Amount = lp.Amount,
IsDiscard = lp.IsDiscarded,
DiscardRemarks = lp.DiscardRemarks
}).DefaultIfEmpty(ObjNull));
List<ObjGetAllPendingPmntDetails> test = testquery.ToList();
This query gives the following Exception Message -
Unable to create a constant value of type CashVitae.ObjGetAllPendingPmntDetails. Only primitive types or enumeration types are supported in this context.
I got this Exception after I added the SQL function statement to convert le.FreqId which is a byte to a string as ToString() is not recognized in the LINQ Expression Store.
ObjGetAllPendingPmntDetails is a partial class in my model which is added as it is used too many times in the code to bind data to tables.
It has both IDs as long, 'Amount' as decimal, PmntDtTm as Datetime,IsDiscard as bool and remaining all are string including 'Ref'.
I get no results as currently no data satisfies the condition. While trying to handle null, I added DefaultIfEmpty(ObjNull) and ObjNull has all properties initialized as follows.
ObjGetAllPendingPmntDetails ObjNull = new ObjGetAllPendingPmntDetails()
{ Id = 0, Table = "-", loanEMIId = 0, Name = "-", Ref = "-",
PmntDtTm = Convert.ToDateTime("01-01-1900"),
Amount = 0, IsDiscard = false, DiscardRemarks = "" };
I need this query to work fine as it has Union() called on it with 5 other queries. All returning the same ObjGetAllPendingPmntDetails columns. But there is some problem as this query has no data satisfying the conditions and the Exception Shared Above.
Any suggestions are appreciated as I am unable to understand the root cause of the problem.
#AndrewCoonce is right, the .DefaultIfEmpty(ObjNull) is the culprit here. Entity Framework turns DefaultIfEmpty into something like...
CASE WHEN ([Project1].[C1] IS NULL) THEN #param ELSE [Project1].[Value] END AS [C1]
...but there's no way to coerce an instance of ObjGetAllPendingPmntDetails into something that can take the place of #param, so you get an exception.
If you move the DefaultIfEmpty call to after the ToList it should work correctly (although you'll need to call ToList again after that if you really want a concrete list instance).

Entity Framework: Any or All - Unable to create a constant value of type 'System.Collections.Generic.List`1'

I am trying to do something like this:
from t in ent.myEntities
where SelectedProperties == null || SelectedProperties.Any(le => le == t.Entity)
select t
basically trying to cover 2 cases. accepting an empty list, should return all entities, or filter on the list if it is supplied.
above actually does work when i supply the list, however in the case when it is null i get:
Unable to create a constant value of type
'System.Collections.Generic.List`1'. Only primitive types ('such as
Int32, String, and Guid') are supported in this context
also tried using this with a string array:
where arr == null || arr.Contains(t.Entity)
is it possible to have such a condition without having to build a predicate (which is a bigger effort)?
You might want to try using the list in a simpler way:
where SelectedProperties == null || SelectedProperties.Contains(t.Entity)
It may well not work, but it's worth a try. Otherwise, if this is really your whole query, I'd just write it as:
var query = SelectedProperties == null
? ent.myEntities
: ent.myEntities.Where(t => SelectedProperties.Contains(t.Entity));
EDIT: Okay, if you have to use Any, and have lots of these to compose, you can do it like this:
var query = ent.myEntities;
if (SelectedProperties != null)
{
query = query.Where(t => SelectedProperties.Any(x => x == t.Entity));
}
if (SomethingElse)
{
query = query.Where(...);
}
// etc
I'm using EF5, something like this will fix the issue:
ent.myEntities.ToList().Where(t => SelectedProperties == null || SelectedProperties.Contains(t.Entity));

Why is the sum of an empty set null?

If I do:
int updateGamePlays = db.tblArcadeGames.Where(c => c.ParentGameID == GameID).Sum(c => c.Plays);
If no records are returned in this query it throws:
System.InvalidOperationException: The null value cannot be assigned to
a member with type System.Int32 which is a non-nullable value type.
The only way to get it to return 0 is by doing:
int updateGamePlays = db.tblArcadeGames.Where(c => c.ParentGameID == GameID).Sum(c => (int?)c.Plays) ?? 0;
In the database c.Plays is a non-nullable int.
In set theory the sum of an empty set should equal 0 (ref). How comes in Linq-to-SQL did they decide to make it return null?
According to a source at Microsoft, Sum() on an empty set is null because of the way it works in SQL:
when the table is empty i´m getting this exception: InvalidOperationException
In SQL, Sum() aggregate operator returns null for an empty set. So this is as designed.
Another alternative is to add a 0 to the set to make sure there's always at least one value.
int updateGamePlays = db.tblArcadeGames.Where(c => c.ParentGameID == GameID)
.Select(c => c.Plays)
.Concat(new [] { 0 })
.Sum();
You can use the more general Aggregate method with a seed of zero:
int updateGamePlays = db.tblArcadeGames
.Where(c => c.ParentGameID == GameID)
.Aggregate(0, (a, c) => a + c.Plays);
This does not require using nullable types.

Could not resolve property for Average linq to NHibernate mapped object

I have code that calculate average number of days from date opened to date closed.
When i run the expression using Linq and lambda expression i get error as follows:
Error message: could not resolve property: DateClosed.DateCreated of:
TestProject.LegalWork
where code is:
var result = Repository.All
.Where(x => x.DateClosed != null)
.Average(x => ((DateTime)x.DateClosed - x.DateCreated).TotalDays);
How ever when i run this using loop and filter on condition only, eveything work fine.
int number= 0;
decimal totalDays = 0;
foreach (LegalWork legalWork in Repository.All.Where(x => x.DateClosed != null))
{
totalDays += (decimal)((DateTime)legalWork.DateClosed - legalWork.DateCreated).TotalDays;
number++;
}
return (totalDays == 0 || numberOfLegalWork ==0 ) ? 0 : Convert.ToDecimal(totalDays/numberOfLegalWork);
What is wrong in Linq and Lambda version?
I'm sure you can't call to:
x.DateClosed - x.DateCreated
or givenDate.TotalDays in linq2nhibernate, because you should call a specific function of DateTime which is not part of linq2nhibernate it's part of .net framework and it doesn't implemented in linq2nhibernate, but your current error message says another thing, to solve ur problem currently u can do:
var result = Repository.All.Where(x => x.DateClosed != null).ToList()
.Average(x => ((DateTime)x.DateClosed - x.DateCreated).TotalDays);
if there is problem with above code, please insert ur class definition,
but sure it's not a best solution, it's better to write a stored procedure and call it.

LINQ query result in int type variable

I want the the LINQ query result in int type variable.
i have a query this will always return the single int value. i want result sumthing like that.
int interlineId = from cSInterline in codeShareInterline_.AsEnumerable()
where cSInterline.Field<int>("InterCodeId") == interCodeId[0]
select cSInterline.Field<int>("PermitedPercent");
But it returning the error..
Your query is returning an IEnumerable<int>, with only one item in this case. So add Single or SingleOrDefault onto the end to return only that 1 item. If your query might return more than 1 item then use FirstOrDefault.
int interlineId =
(from cSInterline in codeShareInterline_.AsEnumerable()
where cSInterline.Field<int>("InterCodeId") == interCodeId[0]
select cSInterline.Field<int>("PermitedPercent")).SingleOrDefault();
Try this:
int interlineId = (from cSInterline in codeShareInterline_.AsEnumerable()
where cSInterline.Field<int>("InterCodeId") == interCodeId[0]
select cSInterline).Single().Field<int>("InterCodeId");
Try this (it should work):
int? interlineId = (from cSInterline in codeShareInterline_.AsEnumerable()
where cSInterline.Field<int>("InterCodeId") == interCodeId[0]
select cSInterline.Field<int>("PermitedPercent")).FirstOrDefault();

Resources