multiple where in linq based on parameters value [duplicate] - c#

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.

Related

how to conditionally add where condition in linq [duplicate]

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))

Joining table to a list using Entity Framework

I have the following Entity Framework function that it joining a table to a list. Each item in serviceSuburbList contains two ints, ServiceId and SuburbId.
public List<SearchResults> GetSearchResultsList(List<ServiceSuburbPair> serviceSuburbList)
{
var srtList = new List<SearchResults>();
srtList = DataContext.Set<SearchResults>()
.AsEnumerable()
.Where(x => serviceSuburbList.Any(m => m.ServiceId == x.ServiceId &&
m.SuburbId == x.SuburbId))
.ToList();
return srtList;
}
Obviously that AsEnumerable is killing my performance. I'm unsure of another way to do this. Basically, I have my SearchResults table and I want to find records that match serviceSuburbList.
If serviceSuburbList's length is not big, you can make several Unions:
var table = DataContext.Set<SearchResults>();
IQuerable<SearchResults> query = null;
foreach(var y in serviceSuburbList)
{
var temp = table.Where(x => x.ServiceId == y.ServiceId && x.SuburbId == y.SuburbId);
query = query == null ? temp : query.Union(temp);
}
var srtList = query.ToList();
Another solution - to use Z.EntityFramework.Plus.EF6 library:
var srtList = serviceSuburbList.Select(y =>
ctx.Customer.DeferredFirstOrDefault(
x => x.ServiceId == y.ServiceId && x.SuburbId == y.SuburbId
).FutureValue()
).ToList().Select(x => x.Value).Where(x => x != null).ToList();
//all queries together as a batch will be sent to database
//when first time .Value property will be requested

Conditionally Insert Where Clause in LINQ Method Syntax with Select Many

Not sure if this possible using the LINQ method chain syntax or at all, but I would like to conditionally insert a where class in the chain if a parameter passed to the method is not null.
Here is the redundant code I would like to simplify:
public ICollection<Organization> getNetworkServiceRecipients(string serviceId = null)
{
ICollection<Organization> children = get_all_children();
if (serviceId != null)
{
return children.SelectMany(o => o.receives_these_services)
.Where(s => s.serviceId == serviceId)
.Select(o => o.serviceRecipient)
.Distinct()
.ToList();
}
else
{
return (children.SelectMany(o => o.receives_these_services)
.Select(o => o.serviceRecipient)
.Distinct()
.ToList());
}
}
I have been trying to insert the where clause programmatically based on whether serviceId is null or not. All of the answers I have found where based on the query syntax, but I couldn't translate. Any suggestions?
If you don't want to have it in the actual where query as dotnetom mentioned, you can do something like this:
public ICollection<Organization> getNetworkServiceRecipients(string serviceId = null)
{
var services = get_all_children().SelectMany(o => o.receives_these_services);
if (serviceId != null)
services = services.Where(s => s.serviceId == serviceId);
return services.Select(o => o.serviceRecipient)
.Distinct()
.ToList();
}
You can try this approach:
public ICollection<Organization> getNetworkServiceRecipients(string serviceId = null)
{
ICollection<Organization> children = get_all_children();
return children.SelectMany(o => o.receives_these_services)
.Where(s => serviceId == null || s.serviceId == serviceId)
.Select(o => o.serviceRecipient)
.Distinct()
.ToList();
}
In this case if your variable serviceId is null then only the first part of where condition would be executed, otherwise first part would be true and only second condition would matter.
Similar answer as dotnetom, but uses a ternary to determine which lambda to use
so that serviceId == null doesn't get executed on a per-item basis.
return children.SelectMany(o => o.receives_these_services)
.Where( serviceId == null ? (_ => true) : (s => s.serviceId == serviceId))
.Select(o => o.serviceRecipient)
.Distinct()
.ToList();

filtering results with Entity Framework

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();

Change query value based on parameter [duplicate]

This question already has answers here:
Creating reusable Linq queries
(6 answers)
Closed 8 years ago.
I have a query:
doc.NonFinancialAssetSection.NonFinancialAssets
.Where(m => m.Owner.Id == ownerId && m.InvestableAsset == true)
.Sum(s => s.CurrentValue);
I need to change the value of s.CurrentValue to s.ProposedValue, however rather than copying and pasting the query again, is there any way i can have this value dependant on a parameter passed into the controller?
Yes, you can do this:
var query = doc.NonFinancialAssetSection.NonFinancialAssets
.Where(m => m.Owner.Id == ownerId && m.InvestableAsset == true);
var sum = (condition)
? query.Sum(s => s.CurrentValue)
: query.Sum(s => s.ProposedValue);
You could also do this:
var sum = doc.NonFinancialAssetSection.NonFinancialAssets
.Where(m => m.Owner.Id == ownerId && m.InvestableAsset == true)
.Sum(s => (condition) ? s.CurrentValue : s.ProposedValue);
Or this:
Func<NonFinancialAsset, double> sumProperty = (condition)
? s => s.CurrentValue
: s => s.ProposedValue;
var sum = doc.NonFinancialAssetSection.NonFinancialAssets
.Where(m => m.Owner.Id == ownerId && m.InvestableAsset == true)
.Sum(sumProperty);

Categories

Resources