I have the following LINQ statement:
var inspectorAllocSummary = context
.UserDetails
.Where(ud => ud.PerformAudit == true && ud.Valid == true)
.OrderBy(ud => ud.Firstname)
.Select(ud
=> new InspectorWorkStatusModel
{
InspectorName = ud.Firstname,
ToBeCompleted = context
.InspectorWorkAllocations
.Where(x => x.UploadCOESDetails.AuditMonth
== criteria.AuditMonth
&& x.InspectorId == ud.Id)
.Sum(x=> x.ToBeAudited) ?? 0,
Completed = context
.COESDetails
.Where(x => x.UploadCOESDetails.AuditMonth
== criteria.AuditMonth
&& x.InspectorId == ud.Id
&& x.AuditType != null)
.Count()
});
The ToBeCompleted is an integer, it gets data from the database, but if it is null I want to make sure it is set to 0. I tried the following:
ToBeCompleted = context
.InspectorWorkAllocations
.Where(x => x.UploadCOESDetails.AuditMonth == criteria.AuditMonth
&& x.InspectorId == ud.Id)
.Sum(x=> x.ToBeAudited) ?? 0
but I get the following error:
Operator '??' cannot be applied to operands of type 'int' and 'int'
How can I ensure that if the return data is null, that it will be set to zero?
If ToBeAudited is an int then Sum can never return null, it always returns an int. If the collection is empty it will return 0. just take off ?? 0.
However, Linq-to-SQL and Linq-to-Entities can throw an error if the resultant SQL does not return any records. For Linq-to-SQL one "fix" is to cast the underlying field to a nullable type:
.Sum(x=> (int?)x.ToBeAudited) ?? 0
For Linq-to-Entities a fix is to call .DefaultIfEmpty():
.Select(x=> x.ToBeAudited)
.DefaultIfEmpty(0)
.Sum()
First, you need to change the type of ToBeAudited to int?. The problem comes from the fact that int is a value type and it cannot contain null. That's why in your first approach you get the error:
The cast to value type 'Int32' failed because the materialized value is null.
There is a Sum overload which accepts nullable values. So after changin ToBeAudited to nullable this will suffice:
ToBeCompleted = context
.InspectorWorkAllocations
.Where(x => x.UploadCOESDetails.AuditMonth == criteria.AuditMonth
&& x.InspectorId == ud.Id)
.Sum(x => x.ToBeAudited).Value;
You don't need the ?? operator, as null values are being automatically ignored (and for the empty sequence Sum will return 0).
Related
I want to check if value of "Acceptance" is "Accepted" and if it has that value- .Sum else i want to get 0, but have some problms with finding correct syntax. I cant get "Acceptance" value
My method
public decimal Prices2(string term)
{
var kl= db.Order.Where(x => x.Client == term && x.Acceptance == "Accepted");
if (term != null && kl.Acceptance == "Accepted" )
{ ^^//Element does not contain definition"Acceptance"
return kl.Sum(x => x.Price);
}
else
{
return 0;
}
}
how I get "term"
public IEnumerable<string> GetClient(string term)
{
return db.Order.Where(x => (term != null && x.Client.Contains(term)) || (term == null)).OrderBy(c => c.Client).Take(10).Select(a => a.Client).Distinct();
}
When i try this:
return db.Order.Where(x => x.Client == term && x.Acceptance == "Accepted").sum(x=>x.Price)
I get error when there is no "Accepted" order for client
System.InvalidOperationException: „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.”
How can i check first if there is Accepted order for client and return 0 if there istn?
First Assign the query to one variable,
var orders = db.Order.Where(x => x.Client == term && x.Acceptance == "Accepted");
var result= orders.Count() > 0 ? orders.Sum(x=>x.Price) : 0.0M;
return result;
You're return type of method should be decimal
.
First of all, your code will not work because variable kl is of type IEnumerable<Order> which doesn't have a property Acceptance.
The code mentioned by #uk2k05 in the comments section will solve your problem:
return db.Order
.Where(x => x.Client == term && x.Acceptance == "Accepted")
.Sum(x => x.Price);
But another problem will occur, that's because Sum method returns Nullable<Decimal>, while your method Prices2 returns decimal. Click to see docs
To solve this problem you can use the following code instead:
return db.Order
.Where(x => x.Client == term && x.Acceptance == "Accepted")
.Sum(x => x.Price) ?? 0;
That will return the value returned by Sum or 0 if the returned value is null.
I Have this query
decimal? query = context.History
.Where(x => x.ItemId == Id
&& x.OtherFilter == IdOtherFilter
&& x.Fecha < Fecha)
.Select(x => x.Secuencia)
.Max();
I need to perform this query into Linq:
select max(Secuencia)
from History
where ItemId= 1406
and OtherFilter= 3
and Fecha < '20150922'
group by OtherFilter
I need to get the max Secuencia from a table that match with criteria, it works fine when criteria returns data, but when no data match with criteria, Max() can't materialize throwing an InvalidOperationException,
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.
how to avoid that ?
There is another Linq that I can use ?
are those sentences equivalent? if not What is wrong in my linq?
Assuming that the type of the Secuencia property is decimal and not decimal?, you should try adding a cast to decimal? so that Max will return null in the case that there are no values.
decimal? query = context.History
.Where(x => x.ItemId == Id
&& x.OtherFilter == IdOtherFilter
&& x.Fecha < Fecha)
.Select(x => (decimal?) x.Secuencia)
.Max();
or
decimal? query = context.History
.Where(x => x.ItemId == Id
&& x.OtherFilter == IdOtherFilter
&& x.Fecha < Fecha)
.Select(x => x.Secuencia)
.Cast<decimal?>()
.Max();
Make following modification to make it work, add DefaultIfEmpty() before Max() call, this will take care of empty list, also you may specify custom default value like 0.0, here it would be null, since the type selected is a nullable value type, check DefaultIfEmpty
decimal? query = context.History
.Where(x => x.ItemId == Id
&& x.OtherFilter == IdOtherFilter
&& x.Fecha < Fecha)
.Select(x => x.Secuencia)
.DefaultIfEmpty()
.Max();
opencall.Priority =
averages.Where(x => x.ProblemCode == opencall.ProblemCode)
.SingleOrDefault().Priority;
The above lambda statement returns some nulls because ProblemCode isn't always guaranteed to be in the averages list.
How can I rewrite this statement so that if that is the case opencall.Priority is set to "" instead of the application throwing an error?
You have to provide a new default value for your reference type, other than null.
opencall.Priority = averages.Where(x => x.ProblemCode == opencall.ProblemCode)
.Select(x => x.Priority)
.DefaultIfEmpty("")
.Single();
So Priority is a string? Note that you don't need SingleOrDefault anymore since the query can never throw an exception, because it will return your provided fallback value.
Split it up:
var result = averages.Where(x => x.ProblemCode == opencall.ProblemCode).SingleOrDefault()
opencall.Priority = result != null ? result.Priority : string.Empty;
Try getting the problem code first, then check if it's null.
var possiblyNullProblemCode=
averages.Where(
x => x.ProblemCode == opencall.ProblemCode)
.SingleOrDefault();
openCall.Priority =
possiblyNullProblemCode == null ?
string.Empty :
possiblyNullProblemCode.Priority;
Assuming Priority is string, you could try:
var average = averages.Where(x => x.ProblemCode == opencall.ProblemCode).SingleOrDefault()
opencall.Priority = average == null ? "" : average.Priority;
You can simply write:
opencall.Priority =
averages.Where(x => x.ProblemCode == opencall.ProblemCode)
.Select(x => x.Priority)
.SingleOrDefault() ?? string.Empty;
This has caused me no end of problems today. I have this simple query
var result =
DataContext.Accommodations.Where(a =>
(criteria.MinPrice == null || a.AccommodationRates.Any(r => r.From >= criteria.MinPrice)) &&
(criteria.MaxPrice == null || a.AccommodationRates.Any(r => r.To <= criteria.MaxPrice)) &&
(criteria.Locations == null || criteria.Locations.Count == 0 || a.AccommodationPlaceJoins.Any(j => criteria.Locations.Contains(j.Place.PlaceName)))
);
The last line of this query is causing me problems
(criteria.Locations == null ||
criteria.Locations.Count == 0 ||
a.AccommodationPlaceJoins.Any(j => criteria.Locations.Contains(j.Place.PlaceName)))
The error it gives is
Unable to create a constant value of type
'System.Collections.Generic.IList`1'. Only primitive types ('such as
Int32, String, and Guid') are supported in this context.
I'm not even trying to create a list. All I'm trying to do here is bring back accommodations which are associated to a place (where the place name in the Place table which is linked to the Accommodation table via the AccommodationPlaceJoin table) is equal to any one of the place names in criteria.Locations (which is of type IList).
I've tried changing this line to this, but it didn't work.
(criteria.Locations == null ||
criteria.Locations.Count == 0 ||
a.AccommodationPlaceJoins.Any(j => criteria.Locations.Any(l => l == j.Place.PlaceName)))
The constant value EF can't create is null for the comparison criteria.Locations == null. You need to split the query into two cases and do the check for the empty list outside of the query, for example like so:
var result = DataContext.Accommodations.Where(a =>
(criteria.MinPrice == null ||
a.AccommodationRates.Any(r => r.From >= criteria.MinPrice)) &&
(criteria.MaxPrice == null ||
a.AccommodationRates.Any(r => r.To <= criteria.MaxPrice)));
if (criteria.Locations != null && criteria.Locations.Count > 0)
{
result = result.Where(a => a.AccommodationPlaceJoins
.Any(j => criteria.Locations.Contains(j.Place.PlaceName)));
}
Edit
BTW: Composing the whole query would make it better readable in my opinion and will simplify the SQL that has to be sent to the database:
IQueryable<Accommodation> result = DataContext.Accommodations;
if (criteria.MinPrice != null)
result = result.Where(a => a.AccommodationRates
.Any(r => r.From >= criteria.MinPrice));
if (criteria.MaxPrice != null)
result = result.Where(a => a.AccommodationRates
.Any(r => r.To <= criteria.MaxPrice));
if (criteria.Locations != null && criteria.Locations.Count > 0)
result = result.Where(a => a.AccommodationPlaceJoins
.Any(j => criteria.Locations.Contains(j.Place.PlaceName)));
I had this same issue when trying to pass a list of strings for comparison into an EF core query recently and found that it resolves the issue to assign an empty array or empty list to the value in case it is null rather than doing the null check right in the EF Core query.
This allows you to query the EF Core database without the null error and you don't need a bunch of conditional branching for separate queries - just one query with a bit of null coalescence.
So your code fixed this way would look like this:
var locations = criteria.Locations == null ? new List<Location>() : criteria.Locations;
var result =
DataContext.Accommodations.Where(a =>
(criteria.MinPrice == null || a.AccommodationRates.Any(r => r.From >= criteria.MinPrice)) &&
(criteria.MaxPrice == null || a.AccommodationRates.Any(r => r.To <= criteria.MaxPrice)) &&
(locations.Any() ? a.AccommodationPlaceJoins.Any(j => criteria.Locations.Contains(j.Place.PlaceName))) : true);
Keep in mind I am not sure of the type for locations or accomodationplacejoins so I cannot be sure the above code will exactly work but the general idea is we are doing a .Any() instead of checking for null. This way we can keep our query a little simpler. We are then using a ternary expression within the last block of our where clause so if the locations list turns out to be empty, we skip the condition entirely and just return true which coalesces the empty list if it is empty.
I have list of transaction objects and want to order them by certain condition depending on view user is currently on.
The problem I have is that in order to add a condition in a where clause, first I need to check if it is null or not to prevent null pointer exception. This causes records with the column null being filtered out(and I want to include them at bottom of the list).
How can I modify the query so that it ignores the conditions(where and order by) if that column is null and still append them to the result set?
This is one example query:
transactions = transactions
.Where(t => t.PurchaseRequisition != null &&
t.Award != null && t.PurchaseRequisition.RequisitionedBy != null)
.OrderBy(t => t.Award.ContractNumber).
ThenBy(t => ToSafeString(t.Award.ContractNumber)).
ThenBy(t => ToSafeString(t.PurchaseRequisition.RequisitionedBy.FullName));
public string ToSafeString(string s)
{
return s ?? String.Empty;
}
// I want records where PurchaseRequisition or Award is null to be appended to the result set.
You simply need to modify your OrderBy and ThenBy clauses:
.OrderBy(t => t.Award == null || t.Award.ContractNumber == null)
.ThenBy(t => t.Award == null ? "" : ToSafeString(t.Award.ContractNumber))
.ThenBy(t => t.PurchaseRequisition == null ? ""
: ToSafeString(t.PurchaseRequisition.RequisitionedBy.FullName));
Now you can completely remove the Where clause.