This question already has answers here:
Linq dynamically adding where conditions
(3 answers)
Closed 2 years ago.
I am using entity framework and i want to add a where condition only if the condition is met else i dont want that where to be executed which i want to do it in 1 query
Context.Test
.Where(v => v.Valuation.ValuationPeriod.PeriodName == periodName && parameters.SelectedTemplateIds.Contains(v.TemplateTypeId) && fundBusinessIds.Contains(v.Fund.BusinessId))
.Where(v => parameters.sortedList.Contains(v.Valuation.PortfolioCompany.DealCode))
.Where(v => wpGroup == null || v.Valuation.PortfolioCompany.WPGroup == wpGroup)
.Where(v => !myDeals || v.Valuation.PortfolioCompany.UserPermission.Any(up => up.UserId == userId))
so in the above query
Where(v => parameters.sortedList.Contains(v.Valuation.PortfolioCompany.DealCode))
I want to execute only if
parameters.sortedList.Count() > 0
else i dont want to include that where condition in the above query. So basically here i know we can do by seperating the query that is first get a list of values and then check this condition and if it matches then add a where on that list. But is it possible without doing that?
The filter could be added contitionally as follows by using an intermediate assignment.
var result = Context.Test.Where(v => v.Valuation.ValuationPeriod.PeriodName == periodName && parameters.SelectedTemplateIds.Contains(v.TemplateTypeId) && fundBusinessIds.Contains(v.Fund.BusinessId));
if (parameters.sortedList.Count() > 0)
{
result = result.Where(v => parameters.sortedList.Contains(v.Valuation.PortfolioCompany.DealCode));
}
result = result.Where(v => wpGroup == null || v.Valuation.PortfolioCompany.WPGroup == wpGroup)
.Where(v => !myDeals || v.Valuation.PortfolioCompany.UserPermission.Any(up => up.UserId == userId));
You can use this
.Where(v => parameters.sortedList.Count() > 0 ?
parameters.sortedList.Contains(v.Valuation.PortfolioCompany.DealCode) : true)
LINQ queries don't execute unless you do something that causes enumeration of the resulting IEnumerable, which means you can have a pattern of:
var x = collection.Where(...);
if(sometest)
x = x.Where(..);
var result = x.ToList(); //enumerate, causing evaluation
If sometest is true then both the Where will apply (AND style; both where predicates would have to result in a true for a collection entity to appear in the result), if sometest is false, then only the first Where applies
You can add an extension
public static class WhereIfExtension
{
public static IEnumerable<TCollection> WhereIf<TCollection>(this IEnumerable<TCollection> source,
bool condition, Func<TCollection, bool> predicate)
{
return condition ? source.Where(predicate) : source;
}
public static IQueryable<TCollection> WhereIf<TCollection>(this IQueryable<TCollection> source, bool condition,
Expression<Func<TCollection, bool>> predicate)
{
return condition ? source.Where(predicate) : source;
}
}
then
Context.Test
.Where(v => v.Valuation.ValuationPeriod.PeriodName == periodName && parameters.SelectedTemplateIds.Contains(v.TemplateTypeId) && fundBusinessIds.Contains(v.Fund.BusinessId))
.WhereIf(parameters => parameters.sortedList.Count() > 0, parameters.sortedList.Contains(v.Valuation.PortfolioCompany.DealCode))
.Where(v => wpGroup == null || v.Valuation.PortfolioCompany.WPGroup == wpGroup)
.Where(v => !myDeals || v.Valuation.PortfolioCompany.UserPermission.Any(up => up.UserId == userId))
Related
Hi this question has been asked before but I'm struggling to find an answer that matches my question (the error comes up a lot).
This looks to be similar but with 4 years ago has there been any progress.
LINQ to Entities does not recognize the method 'Int32
Basically I want to move a subquery that returns a count into a function anyway here's the code.
vm.SicknessEpisodes = _db.SicknessEpisodes.Where(x => x.Status == true && x.LastDay == null).OrderByDescending(x => x.FirstDay).
Select(x => new HomeSicknessEpisode
{
SicknessEpisode = x,
EpisodesIn12Months = _db.SicknessEpisodes.Where(y => y.StaffID == x.StaffID && y.Status == true &&
(y.LastDay == null || (y.LastDay.HasValue && y.LastDay >= prevDate))).Count()
}).
ToPagedList(p, 100);
This works
This
vm.SicknessEpisodes = _db.SicknessEpisodes.Where(x => x.Status == true && x.LastDay == null).OrderByDescending(x => x.FirstDay).
Select(x => new HomeSicknessEpisode
{
SicknessEpisode = x,
EpisodesIn12Months = _db.episodes12Months(x,prevDate).Count()
}).
ToPagedList(p, 100);
public IQueryable<SicknessEpisode> episodes12Months(SicknessEpisode x, DateTime prevDate)
{
return this.SicknessEpisodes.Where(y => y.StaffID == x.StaffID && y.Status == true &&
(y.LastDay == null || (y.LastDay.HasValue && y.LastDay >= prevDate)));
}
Does not.
Can anyone tell me how I can make it work - ideally without going into a List and then foreach each episode to run the count.
I'm just trying to make it as efficient as possible for Entity Framework.
If it's not possible - then that's fine - one of those things.
I must to execute this expression:
var CAP = modelCap.AZCPC00F.Where(x => x.CPCVER == CPCVER && x.CPCNAR == CPCNAR && x.CPCCAP == CPCCAP)
.Where(x => XXXXKG == 0 ? true : Convert.ToInt64(Convert.ToDouble(x.CPCLKG)) < XXXXKG)
.Where(x => XXXXMC == 0 ? true : Convert.ToInt64(Convert.ToDouble(x.CPCLMC)) < XXXXMC)
.Where(x => XXXXFD == "N" ? true : x.CPCZFD == XXXXFD).FirstOrDefault();
When I try to execute this I have an exception on the internal conversion of x.CPCLKG. The exception is:
LINQ to Entities does not recognize the method 'int64' method, and this method cannot be translated into a store expression.
I know that the problem is in the conversion but how can i use this function?
An example of x.CPCLKG is 9.9999 and is an nChar character type.
Thanks to all
You need to have the logic that is not supported in Linq To Entities done in an in-memory query. We can do this by calling ToList() on the parts of the query that are supported. This will execute those parts, and return the results as a list. We can then execute whatever Linq supports on that list, in memory.
var CAP = modelCap.AZCPC00F.Where(x => x.CPCVER == CPCVER && x.CPCNAR == CPCNAR && x.CPCCAP == CPCCAP)
.Where(x => XXXXFD == "N" ? true : x.CPCZFD == XXXXFD)
.ToList();
var CAP2 = CAP.Where(x => XXXXKG == 0 ? true : Convert.ToInt64(Convert.ToDouble(x.CPCLKG)) < XXXXKG)
.Where(x => XXXXMC == 0 ? true : Convert.ToInt64(Convert.ToDouble(x.CPCLMC)) < XXXXMC).FirstOrDefault()
This question already has answers here:
Linq to SQL multiple conditional where clauses
(3 answers)
Closed 7 years ago.
I want to have multiple where clauses in linq but out of them only one should execute, i was trying something like this:
public JsonResult GetPost(int? id, int? tagid, DateTime? date)
{
var ret = from data in db.Posts.Include(x => x.Tags)
.Include(x => x.Neighbourhood)
.Where((x => x.NeighbourhoodId == id) || (y => y.PostedDate == date) || third condition).ToList()
but i was unable to put second and third condition there becoz after putting dot after y, i cant see any options.
Now, out of these three, only one parameter would have value and other two would have null so, it should checks for parameter only with value.
should i write query like this, is it correct way:
if (id != null)
{
//whole query here
}
else if (tagid != null)
{
//whole query here
}
else (date != null)
{
//whole query here
}
Is it the best way to do this or something else is possible. many many thnks in advance for any suggestion.
Something like this?
var ret = from data in db.Posts.Include(x => x.Tags)
.Include(x => x.Neighbourhood)
.Where(x => x.NeighbourhoodId == (id ?? x.NeighbourhoodId) &&
x.<condition> == (tagid ?? x.<condition>) &&
x.PostedDate == (date ?? x.PostedDate).ToList();
Or like this:
var ret = from data in db.Posts.Include(x => x.Tags)
.Include(x => x.Neighbourhood)
.Where(x => id.HasValue ? x.NeighbourhoodId == id :
tagid.HasValue ? x.<condition> == tagid :
x.PostedDate == date).ToList();
Another option is to build your query more dynamically. I think this also makes your code more human readable, and your conditions can be more complex if needed (for example, build your query inside a loop or something). And you can use this with any other operator, like Include etc. Once your query is built, you can call ToList().
var ret = db.Posts.Include(x => x.Tags).Include(x => x.Neighbourhood);
if (id != null)
{
ret = ret.Where((x => x.NeighbourhoodId == id);
}
else
{
...
}
var result = ret.ToList();
You could use the following:
var ret = from data in db.Posts.Include(x => x.Tags)
.Include(x => x.Neighbourhood)
.Where(x => id == null || x.NeighbourhoodId == id)
.Where(x => date == null || y.PostedDate == date)
.ToList();
If the paramter is null, the where-clauses returns every element of the sequence. If its not null it only returns the elements which matches.
another kinda newbie question I guess. I have EF setup and now I want to select some records based on a filter. I have SomeClass with 4 items (all strings to keep things simple, lets call them string1, string2, and so on). Now, in a post I send the filter in an instance of SomeClass, but maybe not all properties are filled in.
So you might end up with string1="something", string2="bla" and string4="bla2". So string 3 = null. Now, how do I setup the query? If i try something like:
var dataset = entities.mydatabase
.Where(x => x.string1 == someclass.string1 && x.string2 == someclass.string2 && x.string3 == someclass.string3 && x.string4 == someclass.string4)
.Select(x => new { x.string1, x.string2, x.string3, x.string4}).ToList();
... I get no results, because string3=null. I could do something with checking all parameters and see if they're set and create the query based on that, but there must be something more elegant than that.
Anyone?
Thanks!
Ronald
The following will return all rows where the someclass.string is null OR equals to x.string.
var dataset = entities.mydatabase
.Where(x => someclass.string1 == null || x.string1 == someclass.string1)
.Where(x => someclass.string2 == null || x.string2 == someclass.string2)
.Where(x => someclass.string3 == null || x.string3 == someclass.string3)
.Where(x => someclass.string4 == null || x.string4 == someclass.string4)
.Select(x => new { x.string1, x.string2, x.string3, x.string4}).ToList();
I have the following code which returns correctly IF I have ALL four strings filled. However, if one of those strings is empty, the list returned is empty. Basically, I need it to return a list even if 1 or more or even ALL of the strings are empty.
private List<Search> FilterSearchResults(List<Search> results)
{
string _dataType = cmbISDataType.SelectedItem.ToString();
string _medium = cmbISMedium.SelectedItem.ToString();
string _pStatus = cmbISPStatus.SelectedItem.ToString();
string _rStatus= cmbISRStatus.SelectedItem.ToString();
return results
.Where(a => a.Data_Type == _dataType && !string.IsNullOrWhiteSpace(_dataType))
.Where(b => b.Medium == _medium && !string.IsNullOrWhiteSpace(_medium))
.Where(c => c.PStat== _pStatus && !string.IsNullOrWhiteSpace(_pStatus ))
.Where(d => d.RStatus== _rStatus && !string.IsNullOrWhiteSpace(_rStatus))
.ToList();
}
Thanks in advance.
Rather than checking whether or not the value is null in every single iteration of the loop, only perform the check when the string is not null:
private List<Search> FilterSearchResults(List<Search> results)
{
string _dataType = cmbISDataType.SelectedItem.ToString();
string _medium = cmbISMedium.SelectedItem.ToString();
string _pStatus = cmbISPStatus.SelectedItem.ToString();
string _rStatus = cmbISRStatus.SelectedItem.ToString();
IEnumerable<Search> query = results;
if (!string.IsNullOrWhiteSpace(_dataType))
query = query.Where(a => a.Data_Type == _dataType);
if (!string.IsNullOrWhiteSpace(_medium))
query = query.Where(b => b.Medium == _medium);
if( !string.IsNullOrWhiteSpace(_pStatus))
query = query.Where(c => c.PStat == _pStatus);
if( !string.IsNullOrWhiteSpace(_rStatus))
query = query.Where(d => d.RStatus == _rStatus);
return query.ToList();
}
Your current condition specifies that any of the strings can't be null or empty which is why the list is being returned as empty. A where clause in Linq works by returning any object in the collection that satisfies the specified condition. If you were to specify the condition as simply:
results.Where(true);
All objects would be returned.
Using an OR instead of an AND for the is null or empty check will return any object in the list that evaluates true for either of conditions. Therefore if the filter string is empty all objects will be returned, otherwise only the objects which meet the other conditions will be returned.
Update your filters to:
return results
.Where(a => a.Data_Type == _dataType || string.IsNullOrWhiteSpace(_dataType))
.Where(b => b.Medium == _medium || string.IsNullOrWhiteSpace(_medium))
.Where(c => c.PStat== _pStatus || string.IsNullOrWhiteSpace(_pStatus ))
.Where(d => d.RStatus== _rStatus || string.IsNullOrWhiteSpace(_rStatus))
.ToList();