PredicateBuilder null check not added to query - c#

I have a situation where I want to query an accounts table. I want all accounts except accounts where ParentId != null as default.
I have tried the following with the predicate builder, but it does not take effect in the sql query. Any idea how to add the whereClause.And(a => a.ParentId != null); check when using the LinqKit PredicateBuilder?
var whereClause = PredicateBuilder.New<VAccount>(true);
whereClause = whereClause.And(a => a.ParentId != null); // Not added to query
if (dto.OrganisationId != 0)
whereClause = whereClause.Or(a => a.OrganisationId == dto.OrganisationId);
// Other search inputs added etc..

Related

Use winform checkbox to linq query

Hope I am asking this question in the right way.
I am trying to determine the most efficient way to use checkboxes to alter what is returned from my linq query without having to code for every possible combination.
As an example, I have three checkboxes on my winform that represent three columns that I am trying to query
[ ] Year
[ ] Make
[ ] Model
I am using a linq statement to determine the distinct combinations of year make and model through EF
var uniquecombos = cb.MakeModelYear.Where(i => i.Year != null && i.Make != null && i.Model != null).Distinct().ToList();
What I would like to do is use the checkboxes on my winform to drive which fields I include in my query.
So
[x] Year
[x] Make
[ ] Model
would yield
var uniquecombos = cb.MakeModelYear.Where(i => i.Year != null && i.Make != null).Distinct().ToList();
Is there a good way to modify the inputs of the query without having to account for every combination of checkboxes through if statements?
Thanks in advance!
Since you have separate properties you still ned to hceck each one - but you can account for each checkbox combination at the same time:
.Where(i => (
(!cbxYear.Checked || i.Year != null) &&
(!cbxMake.Checked || i.Make != null) &&
(!cbxModel.Checked || i.Model != null)
)
You can do something like this :
var query = cb.MakeModelYear;
if (chkYear.Checked)
query = query.Where(i => i.Year != null);
if (chkMake.Checked)
query = query.Where(i => i.Make != null);
if (chkModel.Checked)
query = query.Where(i => i.Model != null);
var uniquecombos = query.Distinct().ToList();

changing linq to sql query

I have a question regarding a Linq to SQL query.
I have following situation:
I have a search with lots of options, like location, availability, name, language etc ...
For this options i have to execute a query to retrieve the results according to options selected, how can i best do it, i cannot write a linq query like for each possibility and combination of options, but i cannot write one for all of them as it will not work, for example:
from p in context.people where p.location==model.location && p.availability==model.availability .... select p
In this case imagine availability is not selected and should not be searched for, but in this case it will be passed as false, or if location is not set and is null so it will only search for empty locations, although i just need all.
So my question is how do people handle this kind of behaviour with queries?
As you long as you do not execute the linq query immediately you can just add where clauses to it. You can do this for example:
var query = from p in context.people;
if(searchOnLocation)
{
query = query.where(p => p.location == model.location);
}
if(otherSearch)
{
query = query.where(p => p.someOtherProperty == someotherValue);
}
var result = query.ToList();
As long you don't call ToList() on your IQueryable, the linq will not be translated into SQL. It's only in the last call, that the linq will be translated and executed against the database
IQueryable<Person> query = context.people;
if(model.location != null)
query = query.Where(x => x.location == model.location);
if(model.availability != null)
query = query.Where(x => x.availability == model.availability);
// etc
Basically, you can compose more and more restrictions as you go.
If you want to implement query without if condition than you can use following syntax:
var query = context.people.
where(p => p.location == (model.location ?? p.location)
&& p.availability == (model.availability ?? p.availability))
.ToList();

MongoDB Select with QueryBuilder

i'm trying to select values from my database, but currently i'm unable to to it and although i know its the fact that the method doesnt except the QueryBuilder class as a parameter, i dont know what to do about it. I only found solutions for querys with one parameter or all parameters are not null. In my case i've a List with ID, and 4 parameters which dont have to be passed to the function so they could be null.
My current code looks like this.
collection = db.GetCollection<Datapoint>("test");
var query = new QueryBuilder<Datapoint>();
var queryattributes = new List<IMongoQuery>();
var ids = new List<IMongoQuery>();
// Add all Attributes if there
if (fromdate != null)
{
BsonDateTime from = BsonDateTime.Create(fromdate);
queryattributes.Add(Query.GTE("UTCTimestamp", from));
}
if (to != null)
{
BsonDateTime bto = BsonDateTime.Create(to);
queryattributes.Add(Query.LTE("UTCTimestamp", bto));
}
if (evId != null)
{
queryattributes.Add(Query.EQ("EvId", evId));
}
if (evType != null)
{
queryattributes.Add(Query.EQ("EvType", evType));
}
// Add all ID's
Parallel.ForEach(idList, data =>
{
lock (query)
{
ids.Add(Query.EQ("CId", data));
}
});
// But everything in the Query
query.Or(ids);
// Add Queryattributes if there
if (queryattributes.Count > 0)
{
query.And(queryattributes);
}
var result = collection.FindAs<Datapoint>(query);
I'm trying to do it without Linq, since i found countless of test, which say that linq is much much slower, and since i want to run it as an Databasetest, i kinda need the performace to execute alot of querys.
The Linq query looks like this
var query2 =
from e in collection.AsQueryable<Datapoint>()
where idList.Contains(e.CId)
&& (evtId == null || e.EvId == evId)
&& (evType == null || e.EvType == evType.Value)
&& (fromdate == null || Query.GTE("UtcTimestamp", BsonDateTime.Create(fromdate)).Inject())
&& (to == null || Query.LT("UtcTimestamp", BsonDateTime.Create(to)).Inject())
select e;
The QueryBuilder doesn't save a query inside it. You use it to generate a IMongoQuery and then use that query to actually query the database.
It seems the end of your code should look like this;
// But everything in the Query
IMongoQuery mongoQuery = query.Or(ids);
// Add Queryattributes if there
if (queryattributes.Count > 0)
{
mongoQuery = query.And(queryattributes);
}
var result = collection.FindAs<Datapoint>(mongoQuery);

Dynamic Linq Query Help?

How do you write a dynamic Linq query for the following simple search criteria?
1) StudentNumber
2) LastName
3) LastName and FirstName
//if (!String.IsNullOrEmpty(StudentNumber))
var results = (from s in Students
where s.StudentNumber == 1001
select s
);
//else if (!String.IsNullOrEmpty(LastName) & (String.IsNullOrEmpty(FirstName))
var results = (from s in Students
where s.LastName == "Tucker"
select s
);
//else if (!String.IsNullOrEmpty(LastName) & (!String.IsNullOrEmpty(FirstName))
var results = (from s in Students
where s.LastName == "Tucker" && s.FirstName == "Ron"
select s
);
You need to declare your results variable outside of any individual query. This will allow you append different filters based upon your varying criteria, and append as many filters as you need. An example:
var results = Students.AsEnumerable(); // use .AsQueryable() for EF or Linq-to-SQL
if (!string.IsNullorEmpty(StudentNumber))
{
results = results.Where(s => s.StudentNumber.Equals(StudentNumber));
}
else if (!string.IsNullOrEmpty(LastName))
{
results = results.Where(s => s.LastName.Equals(LastName));
if (!string.IsNullOrEmpty(FirstName))
{
results = results.Where(s => s.FirstName.Equals(FirstName));
// filter is in addition to predicate against LastName
}
}
// results can be used here
If dealing with Linq-to-Entities or -Sql, type the initial query with Students.AsQueryable(); so that the filtering happens at the database rather than inside the application.
Is there a way I can construct the WHERE clause first and use it in a
Linq query without if...else
If you want to build the entire where before the first step of the query, it's the same logic. You are conditionally building the predicate, so you will have some sort of if/else involved. However, to build the entire predicate first, you could build against a Func<Student, bool> for Linq to Objects.
Func<Student, bool> predicate;
if (!string.IsNullOrEmpty(StudentNumber))
{
predicate = s => s.StudentNumber.Equals(StudentNumber);
}
else if (!string.IsNullOrEmpty(LastName))
{
predicate = s => s.LastName.Equals(LastName);
if (!string.IsNullOrEmpty(FirstName))
{
Func<Student, bool> p = predicate;
predicate = s => p(s) && s.FirstName.Equals(FirstName);
}
}
else
{
predicate = s => true;
}
var query = Students.Where(predicate);
You'll notice it's the exact same if/else structure. You could collapse that down into a complicated conditional expression
Func<Student, bool> predicate;
predicate = s =>
!string.IsNullOrEmpty(StudentNumber)
? s.StudentNumber.Equals(StudentNumber)
: !string.IsNullOrEmpty(LastName)
? !string.IsNullOrEmpty(FirstName)
? s.LastName.Equals(LastName) && s.FirstName.Equals(FirstName)
: s.LastName.Equals(LastName)
: true;
var query = Students.Where(predicate);
But I find that pretty well difficult to follow, certainly as compared to the longer if/else. This predicate is also bigger than the one we build via the if/else, because this one contains all the logic, it's not just the logic we conditionally added.

Linq: how to exclude condition if parameter is null

I have some table and the following condition of query: if parameter A is null take all, if not, use it in the query. I know how to do that in 2 steps:
List<O> list = null;
if (A = null)
{
list = context.Obj.Select(o => o).ToList();
}
else
{
list = context.Obj.Where(o.A == A).ToList();
}
Is it possible to have the same as one query?
Thanks
How about:
list = context.Obj.Where(o => A == null || o.A == A)
.ToList();
You can do it in one query but still using a condition:
IEnumerable<O> query = context.Obj;
if (A != null)
{
query = query.Where(o => o.A == A);
}
var list = query.ToList();
Or you could use a conditional operator to put the query in a single statement:
var query = A is null ? context.Obj : context.Obj.Where(o => o.A == A);
var list = query.ToList();
I would personally suggest either of the latter options, as they don't require that the LINQ provider is able to optimise away the filter in the case where A is null. (I'd expect most good LINQ providers / databases to be able to do that, but I'd generally avoid specifying a filter when it's not needed.)
I opted for
var list = context.Obj.Where(o => A.HasValue ? o.a == A : true);
I would probably write the query like this:
IQueryable<O> query = context.Obj;
if (A != null)
query = query.Where(o => o.A == A);
var list = query.ToList()
It's not one expression, but I think it's quite readable.
Also, this code assumes that context.Obj is IQueryable<O> (e.g. you are using LINQ to SQL). If that's not the case, just use IEnumerable<O>.

Categories

Resources