How can I make a linq search that ignores nulls (or nullables)?
I have a method
IEnumerable<X> Search(int? a, int? b, int? c)
And I want it to return matches on any of the ints? that are not null.
IE: if a and c have values 1 and 9 and b is null the search should render (roughly) to
SELECT *
FROM [TABLE]
WHERE a = 1
AND c = 9
My real method will have 5+ paramters, so iterating combinations is right out.
IEnumerable<X> query = items;
if (a.HasValue) {
query = query.Where(x => x.a == a.Value)
}
if (b.HasValue) {
query = query.Where(x => x.b == b.Value)
}
if (c.HasValue) {
query = query.Where(x => x.c == c.Value)
}
var result = from row in table
where (!a.HasValue || row.a == a.Value)
&& (!b.HasValue || row.b == b.Value)
&& (!c.HasValue || row.c == c.Value)
select row;
Related
I have query and I can display values based on condition in SQL. But how can write C# LINQ query is my question.
SELECT Value
FROM db.table
WHERE xxId = 1 AND YYid = 2 AND IsActive = '1' AND IsDeleted = '0'
Result
NNNN
MMMM
TTTT
VVVV
LLLL
I need same query in LINQ C#
var results = db.table
.Select(a => a.xxid == xxid && a.yyid == id &&
a.IsActive && !a.IsDeleted).value;
var results = db.table
.Where(a => a.xxid == xxid && a.yyid == id && a.IsActive && !a.IsDeleted)
.Select(a => a.value)
.ToList();
Using this Linq code I get any values corresponding to the search input i.e if I search country = Italy and gender = female I get both employees from Italy and employees who are female but I need it to be more specific.
i.e if I search Country = Italy and Gender = female I need to get female employees from Italy. Please suggest me a Linq code for the same
Also, I have five search inputs (First Name, Last Name, Designation, Country, Gender) so just (&&) only doesn't do the work here!
Here's the code:
List<Employee> Elist = userdb.Employees
.Where(i => i.FirstName == Fn ||
i.LastName == Ln ||
i.Designation == desig ||
i.Country == country ||
i.Gender == gender)
.ToList();
This is a situation where the nature of IQueryable comes in very useful. You can add Where clauses to your query without actually executing anything against the database. The SQL would only be executed when you materialise the data, for example using ToList(). This is called deferred query execution.
So you can write your code like this:
IQueryable<Employee> query = userdb.Employees;
if(!string.IsNullOrEmpty(Fn))
{
query = query.Where(e => e.FirstName == Fn);
}
if(!string.IsNullOrEmpty(Ln))
{
query = query.Where(e => e.LastName == Ln);
}
// etc. etc.
List<Employee> Elist = query.ToList();
Most likely, you are not wanting to include criteria that is not filled in. You would only want to filter by a value if the value exists (or is not null). Use an IQueryable to build your search and then assign it to Elist.
IQueryable<Employee> Query = userdb.Employees;
if (Fn != null) {
Query = Query.Where(i => i.FirstName.Equals(Fn));
}
if (Ln != null) {
Query = Query.Where(i => i.LastName.Equals(Ln));
}
if (desig != null) {
Query = Query.Where(i => i.Designation.Equals(desig));
}
if (country != null) {
Query = Query.Where(i => i.Country.Equals(country));
}
if (gender != null) {
Query = Query.Where(i => i.Gender.Equals(gender));
}
List<Employee> Elist = Query.ToList();
Personally I would use a PredicateBuilder here. A small example, let's say you just have 2 queries:
Expression<Func<Person, bool>> hasFirstName = p1 => p1.FirstName == Fn;
Expression<Func<Person, bool>> hasLastName= p2 => p2.LastName == Ln";
You could build this into a predicate builder like so and keep on expanding using any sort of logic:
var predicate = PredicateBuilder.False<Employee>();
if (!string.IsNullOrEmpty(Fn))
{
predicate = predicate.And(e => e.FirstName == Fn);
}
if (!string.IsNullOrEmpty(Ln))
{
predicate = predicate.And(e => e.FirstName == Ln);
}
var result = userdb.Employees.Where(predicate);
Try this
List<Employee> Elist = userdb.Employees
.Where(i => (Fn == null || i.FirstName == Fn ) &&
(Ln == null || i.LastName == Ln ) &&
(desig == null || i.Designation == desig) &&
(country == null || i.Country == country) &&
(gender == null || i.Gender == gender)
.ToList();
I am fetching data using LINQ and Lambda with 2 conditions using this Query. Is it possible to write this logic without if else condition -
public List<Pallet> GetPallet(string palletID, string locationID)
{
List<Pallet> data = new List<Pallet>();
if (locationID != null)
data = data.Where(x => x.PalletID == palletID && x.LocationID == locationID).ToList();
else
data = data.Where(x => x.PalletID == palletID).ToList();
return data;
}
Sure it is:
public List<Pallet> GetPallet(string palletID, string locationID)
{
List<Pallet> data = new List<Pallet>();
data = data.Where(x => x.PalletID == palletID && (locationID == null || x.LocationID == locationID)).ToList();
return data;
}
This is a way of doing it with correct results:
data = data
.Where(x => x.PalletID == palletID)
.Where(!string.IsNullOrEmpty(locationID)? x.LocationID == locationID : true)
.ToList();
NOTE: The accepted answer will return the wrong result although the syntax is correct. It'll always compares the LocationID even if the locationID is null or empty. Note that, in case of locationID == null we do not want to compare at all (we don't want this: x => x.LocationID == null).
I have the below code which works but I do not feel this is the best way to achieve the result. I am looking at optimising my code. Any suggestions of a better option will be appreciated. sub is a subcategory which is nullable.
[AllowAnonymous]
public ActionResult _relatedgrps(string cat, string sub)
{
if (!string.IsNullOrWhiteSpace(sub)){
var pgs = db.Pages
.Where(u=>u.MetaNoSearch==false)
.Where(u => u.PaOk == true && u.Category.Name == cat && u.SubCategory.CatName == sub)
.OrderByDescending(u => u.PaCreatedOn);
return PartialView(pgs.ToList());
}else{
var pgs = db.Pages
.Where(u=>u.MetaNoSearch==false)
.Where(u => u.PaOk == true && u.Category.Name == cat )
.OrderByDescending(u => u.PaCreatedOn);
return PartialView(pgs.ToList());
}}
Linq IEnumerables can be additive and the query will only be executed when enumerated for the first time (like calling .ToList()). So you should be able to do something like this:
var pgs = db.Pages
.Where(u => u.MetaNoSearch == false &&
u.PaOk == true &&
u.Category.Name == cat);
if (!string.IsNullOrWhiteSpace(sub))
{
pgs = pgs.Where(u => u.SubCategory.CatName == sub);
}
return PartialView(pgs.OrderByDescending(u => u.PaCreatedOn).ToList());
Create an object to query it. To improve it, you also could remove it boolean comparations because they are conditions.
var query = db.Pages.Where(u => !u.MetaNoSearch && u.PaOk && u.Category.Name == cat);
if (!string.IsNullOrWhiteSpace(sub))
query = query.Where(u => u.SubCategory.CatName == sub);
query = query.OrderByDescending(u => u.PaCreatedOn);
return PartialView(query.ToList());
#user3021830 - be careful with String.IsNullOrWhitespace, you cannot use that in a database query. You could do String.IsNullOrWhitespace(sub), but not String.IsNullOrWhitespace(u.*).
I'd avoid any conditionals in the query because that will likely result in a case statement in the SQL.
To produce the best SQL I'd do something like this:
var pgs = db.Pages.Where(u => u.MetaNoSearch == false)
.Where(u => u.PaOk == true)
.Where(u => u.Category.Name == cat);
if (!string.IsNullOrWhiteSpace(sub))
{
pgs = pgs.Where(u => u.SubCategory.CatName == sub);
}
var result = pgs.OrderByDescending(u => u.PaCreatedOn).ToList();
I have this linq query that works well (although it may be written better, pls say so if you notice something)
var qry = BenefitCodes
.Where(b => b.BenInterest != 'E'
&& (b.BenProductLine == CoverageProductLine || b.BenProductLine == null) )
.Select(b => b)
.OrderBy(b => b.BenDesc);
A new requirement came down the pipeline to exclude two BenCodes ( 1001, 1009), BenCodes is just another column in the SQL table.
Am I supposed to use some variation of ".Contains", I would have to do !Contains or something. Can anyone point me in the right direction?
Thanks,
~ck in San Diego
Yes, one way to handle this is the following (for brevity and readability, I am excluding the remainder of your query):
var excludedBenCodes = new List<int>() { 1001, 1009 };
var query = BenefitCodes.Where(b => !excludedBenCodes.Contains(b.BenCodes));
I believe this to be more readable and more maintainable than the alternative of adding a subclause b.BenCodes != 1001 && b.BenCodes != 1009 to your where clause.
You could just simply add another line to the Where clause and exclude every itm with a BenCodes of 1001 or 1009.
Like this:
var qry =
BenefitCodes
.Where(b =>
b.BenInterest != 'E' &&
(b.BenProductLine == CoverageProductLine || b.BenProductLine == null) &&
b.BenCodes != 1001 &&
b.BenCodes != 1009)
.Select(b => b)
.OrderBy(b => b.BenDesc);
This might make things a bit more readable, I'd change query to
var qry = BenefitCodes.Where(b => FitsCriteria(b)).OrderBy(b => b.BenDesc);
and add method
public bool FitsCriteria(BenefitCode b)
{
return b.BenInterest != 'E' &&
(b.BenProductLine == CoverageProductLine || b.BenProductLine == null) &&
b.BenCodes != 1001 &&
b.BenCodes != 1009;
}
Kindness,
Dan
var qry = BenefitCodes
.Where(b => b.Code != '1001'
&& b.Code != '1009'
&& b.BenInterest != 'E'
&& ( b.BenProductLine == CoverageProductLine
|| b.BenProductLine == null))
.OrderBy(b => b.BenDesc);
You don't even need the "Select" when you aren't using the LINQ syntax. as the Where and OrderBy methods already return your IQueryable.