Linq tree for nested Expression<Func<>> - exists(select*...) - c#

atm im writting generic filter module in my app.
I have problem with creating proper Expression>. I general SQL query look like:
SELECT distinct ROW_NUMBER
FROM dbo.VIEW_ITEM item
WHERE CODE ='MyName'
AND EXISTS (SELECT *
FROM dbo.VIEW_ITEM
WHERE ROW_NUMBER = item.ROW_NUMBER
AND CODE='MyName'
AND (COL_NUMBER=1 AND DISPLAY='UserName'))
AND EXISTS (SELECT *
FROM VIEW_ITEM
WHERE ROW_NUMBER = item.ROW_NUMBER
AND CODE='MyName'
AND (COL_NUMBER=3 and DISPLAY='2261'))
ORDER BY ROW_NUMBER
This is (in my opinion) best way to get all records I need. I can not use join option because im checking in my AND EXISTS same table as in main query.
So my linq look like:
dboMVI.Where(mvi => mvi.Code == "MyCode")
.Where(mvi => dboMVI.Where(innerMvi => innerMvi.RowNumber == mvi.RowNumber && innerMvi.Code == "MyCode" && innerMvi.ColNumber == 1 && innerMvi.Display == "UserName").Any())
.Where(mvi => dboMVI.Where(innerMvi => innerMvi.RowNumber == mvi.RowNumber && innerMvi.Code == "MyCode" && innerMvi.ColNumber == 3 && innerMvi.Display == "2261").Any())
.Select(mvi => mvi.RowNumber)
.OrderBy(rn => rn)
.Distinct();
That should return me all Rows nnumbers that passed my filtering.
Im managed to create Expression but im sure there is better way to make it more generic and put this in my filtering module not in service from where im passing it to DbContext.
Expression<Func<ViewItem, bool>> filter =mvi =>
dboMVI.Where(innerMvi => innerMvi.RowNumber == mvi.RowNumber
&& innerMvi.Code == "MyCode" && innerMvi.ColNumber == 3 &&
innerMvi.Display == "2261").Any()
And For second filter:
Expression<Func<ViewItem, bool>> filter =mvi =>
dboMVI.Where(innerMvi => innerMvi.RowNumber == mvi.RowNumber
&& innerMvi.Code == "MyCode" && innerMvi.ColNumber == 1 &&
innerMvi.Display == "UserName").Any()
My question is how I can create generic Expression tree for this LINQ query?
I could not find anywhere example of creating such tree.
I found example of passing arguments in join statement.
But in my case im passing from main query number of current row and in subquery its checked if for this specific row any conditions are meet or not.
EDIT: After some comments i noticed i did mistake in rewritting querys from real values to demo. Srry for that hope its fixed now:)
In general its working solution just looking for better way.
EDIT2:
What is my problem here:
im trying to generate from LINQ SQL query that can be consume by EF Core.
in my SQL in using AND EXISTS where in body im referring to same table as in main query. What more in sub query im using ROW_NUMBER from main query.
What is my problem? I dont know how to create expression func (responsible for my sub query) because I dont know how to pass into it my current ROW_NUMBER that im checking. I know how to make expression tree for easy examples. But there I have constant in my body fe int or string . But in this case my const is changing every time to different value so it can not be hard coded.
Answer
I managed to resolve this issue. First of all had to simplify linq query.
dboMVI.Where(mvi => mvi.Code == "MyCode")
.Where(mvi => dboMVI.Any(innerMvi => innerMvi.RowNumber == mvi.RowNumber && innerMvi.Code == "MyCode" && innerMvi.ColNumber == 1 && innerMvi.Display == "UserName"))
.Where(mvi => dboMVI.Any(innerMvi => innerMvi.RowNumber == mvi.RowNumber && innerMvi.Code == "MyCode" && innerMvi.ColNumber == 3 && innerMvi.Display == "2261"))
.Select(mvi => mvi.RowNumber)
.OrderBy(rn => rn)
.Distinct()
Than had to create Expression tree for elements inside Any expression:
IQueryable<MaterializedViewItem> MyDtoList = Enumerable.Empty<MaterializedViewItem>().AsQueryable();
var insideProperty = Expression.Parameter(typeof(MaterializedViewItem), "mviAny");
var baseProperty = Expression.Parameter(typeof(MaterializedViewItem), "mviBaseAny");
MemberExpression condition0Code = Expression.Property(baseProperty, "MvCode");
ConstantExpression condition0CodeValue = Expression.Constant("ARAPP");
var condition0 = Expression.Equal(condition0Code, condition0CodeValue);
var predicateFirstElement = Expression.Lambda<Func<T, bool>>(condition0, baseProperty);
MemberExpression conditionACode = Expression.Property(insideProperty, "MvCode");
ConstantExpression conditionACodeValue = Expression.Constant("MyCode");
var conditionA = Expression.Equal(conditionACode, conditionACodeValue);
MemberExpression conditionACol = Expression.Property(insideProperty, "ColNumber");
ConstantExpression conditionAColValue = Expression.Constant((byte)1);
var conditionB = Expression.Equal(conditionACol, conditionAColValue);
MemberExpression conditionDisplay = Expression.Property(insideProperty, "ValueDisplay");
ConstantExpression conditionDisplayValue = Expression.Constant("UserName");
var conditionC = Expression.Equal(conditionDisplay, conditionDisplayValue);
MemberExpression conditionRow = Expression.Property(insideProperty, "RowNumber");
var newValueToCompare = Expression.PropertyOrField(baseProperty, "RowNumber");
ConstantExpression conditionRowValue = Expression.Constant(0);
var conditionD = Expression.Equal(conditionRow, newValueToCompare);
var condition = Expression.AndAlso(conditionA, conditionB);
var condition2 = Expression.AndAlso(conditionC, conditionD);
var condition3 = Expression.AndAlso(condition, condition2);
var predicate = Expression.Lambda<Func<MaterializedViewItem, bool>>(condition3, insideProperty);
var callCondtions = BuildAny<MaterializedViewItem>(predicate, MyDtoList.Expression);
var myPredicate = Expression.Lambda<Func<T, bool>>(callCondtions, baseProperty);
MemberExpression conditionCol2 = Expression.Property(insideProperty, "ColNumber");
ConstantExpression conditionCol2Value = Expression.Constant((byte)3);
var conditionE = Expression.Equal(conditionCol2, conditionCol2Value);
MemberExpression conditionColDisplay2 = Expression.Property(insideProperty, "ValueDisplay");
ConstantExpression conditionColDisplay2Value = Expression.Constant("2261");
var conditionF = Expression.Equal(conditionColDisplay2, conditionColDisplay2Value);
var condition22 = Expression.AndAlso(conditionA, conditionD);
var condition23 = Expression.AndAlso(conditionE, conditionF);
var condition2Final = Expression.AndAlso(condition22, condition23);
var predicate2 = Expression.Lambda<Func<T, bool>>(condition2Final, insideProperty);
var callCondtions2 = BuildAny<T>(predicate2, MyDtoList.Expression);
Neede extra function to build for me final Any with all parameters
public static Expression BuildAny<T>(Expression<Func<T, bool>> predicate, Expression expression)
{
var overload = typeof(Queryable).GetMethods().FirstOrDefault(method => method.Name == "Any" && method.GetParameters().Count() == 2);
var specificMethod = overload.MakeGenericMethod(typeof(T));
var call = Expression.Call(
specificMethod,
expression,
predicate);
return call;
}
What is important to remember we are building IQueryable based on temporaty object. Later it has to replaced with real db table. It can be done with:
IQueryable<T> queryList = this.DbSet;
var filtersForDbSet = ExpressionTreeConstantReplacer.CopyAndReplace<DbSet<T>, T>(condition, typeof(EnumerableQuery<T>), this.DbSet);
class ExpressionTreeConstantReplacer
{
internal static Expression<Func<T2, bool>> CopyAndReplace<T, T2>(Expression<Func<T2, bool>> expression, Type originalType, T replacementConstant)
{
var modifier = new ExpressionTreeConstantReplacer<T>(originalType, replacementConstant);
var newLambda = modifier.Visit(expression) as LambdaExpression;
return Expression.Lambda<Func<T2, bool>>(newLambda.Body, newLambda.Parameters.FirstOrDefault());
}
}
and
class ExpressionTreeConstantReplacer<T> : ExpressionVisitor
{
Type originalType;
T replacementConstant;
internal ExpressionTreeConstantReplacer(Type originalType, T replacementConstant)
{
this.originalType = originalType;
this.replacementConstant = replacementConstant;
}
protected override Expression VisitConstant(ConstantExpression c)
{
return c.Type == originalType ? Expression.Constant(replacementConstant) : c;
}
}
If anyone will have similar problem in expression tree. Query is build same as in normal query. To pass some vale from main expression to inside expression you have to just show that you are comparing them as:
MemberExpression conditionRow = Expression.Property(insideProperty, "RowNumber");
var newValueToCompare = Expression.PropertyOrField(baseProperty, "RowNumber");
var conditionD = Expression.Equal(conditionRow, newValueToCompare

As i mentioned in the comment to the question, your query can be simpliefied.
[Initial note]
Accordingly to the discussion in comments, i think, your query can be still improved.
[Version #1] - first look
SELECT DISTINCT ROW_NUMBER
FROM dbo.VIEW_ITEM item
WHERE CODE ='MyName'AND COL_NUMBER IN(1, 3) AND DISPLAY IN ('UserName', '2261')
ORDER BY ROW_NUMBER
Based on your SQL query, a Linq version may look like:
int[] nums = {1, 3};
string[] disp = {"UserName", "2261"};
var result = dboMVI
.Where(mvi=> mvi.Code == 'MyName' &&
nums.Any(n=> n.Contains(mvi.ColNumber)) &&
disp.Any(d=> d.Contains(mvi.Display))
.OrderBy(x=>x.RowNumber)
.Select(x=>.RowNumber);
In case when above query does not meet your criteria, you'd try to combine the conditions with parentheses:
[Version #2] - second look
SELECT DISTINCT ROW_NUMBER
FROM dbo.VIEW_ITEM item
WHERE (CODE ='MyName'AND COL_NUMBER IN(1, 3)) AND
(CODE ='MyName' AND DISPLAY IN ('UserName', '2261'))
ORDER BY ROW_NUMBER
A Linq equivalent:
var result = dboMVI
.Where(mvi=> (mvi.Code == 'MyName' &&
nums.Any(n=> n.Contains(mvi.ColNumber))) &&
(mvi.Code == 'MyName' &&
disp.Any(d=> d.Contains(mvi.Display)))
.OrderBy(x=>x.RowNumber)
.Select(x=>.RowNumber);
As you can see, both conditions have to be meet to return data.
[EDIT#2]
As to the Expression... i think it should look like this:
Expression<Func<ViewItem, string, int, string, bool>> filter = (mvi, code, colNo, disp) =>
dboMVI.Any(innerMvi =>
innerMvi.RowNumber == mvi.RowNumber &&
innerMvi.Code==code &&
innerMvi.ColNumber == colNo &&
innerMvi.Display == disp);
[Finall note]
Note: i can't access to your data and i'm not able to guarantee for 100% that above query will meet your criteria.

Related

C# - How to use Expression<Func> with parametrs in LINQ where

Task: I need to give some expression with parameters into LINQ's where to get some data from database, but have an error above
This example of working expression:
var shopExp = GetPersonForShop(PersonTypeIds.Director, new Guid("adda423f-8c38-40e0-9f39-6deceb787bc0")); // id
Where(shopExp)
But i need assign id dynamically, but got error above :
_repository.Persons
.Where(GetPersonForShop(PersonTypeIds.Director, person.PersonId)
And got error:
{"Unable to cast object of type 'System.Linq.Expressions.InstanceMethodCallExpression2' to type 'System.Linq.Expressions.LambdaExpression'."}
How does function for where(linq) look:
private Expression<Func<Person, bool>> GetPersonForShop(PersonTypeIds personTypeId, Guid personId)
{
return person => person .PeronTypeId== (int) personTypeId && person .PersonId == personId;
}
This is approximate look like out production, just change names of parametrs code
How can I add expression with parameters to Where clause??
Lambda expressions use => notation. Try something like this:
var idToFind = new Guid("adda423f-8c38-40e0-9f39-6deceb787bc0");
var result = _repository.Persons
.Where(p => p.TypeId == PersonTypeIds.Director && p.PersonId == idToFind);
In this expression, p represents each Person record in the Persons table, compared one-by-one using the boolean expression that follows it.
Depending on your datasource, the comparison for each p will either be done by .NET in memory, or it will happen inside your database using a SQL WHERE clause which is constructed from the boolean expression. The last would be optimal because it would mean that not the entire Persons table has to be transferred into .NET memory before comparison can take place.
Update - To apply the same condition multiple times without repeating it in your code, while still keeping the advantages of LINQ to SQL translation intact, you can put the condition in an Expression<Func<Person, bool>> object and then use that multiple times:
Expression<Func<Person, bool>> expression =
p => p.TypeId == PersonTypeIds.Director && p.PersonId == idToFind;
var result1 = datasource1.Where(expression);
var result2 = datasource2.Where(expression);
var result3 = datasource3.Where(expression);
Or through a method that produces the Expression object:
var result1 = datasource1.Where(GetExpression(idToFind));
var result2 = datasource2.Where(GetExpression(idToFind));
var result3 = datasource3.Where(GetExpression(idToFind));
public Expression<Func<Person, bool>> GetExpression(Guid idToFind)
{
return p => p.TypeId == PersonTypeIds.Director && p.PersonId == idToFind;
}
Or alternatively you can use a helper method:
var result1 = FilterByTypeAndId(datasource1, idToFind);
var result2 = FilterByTypeAndId(datasource2, idToFind);
var result3 = FilterByTypeAndId(datasource3, idToFind);
public IQueryable<Person> FilterByTypeAndId(IQueryable<Person> datasource, Guid idToFind)
{
return datasource.Where(p => p.TypeId == PersonTypeIds.Director && p.PersonId == idToFind);
}
based on the previous response, I am going to give you a few alternatives and suggestions.
var idToFind = new Guid("adda423f-8c38-40e0-9f39-6deceb787bc0");
var result = _repository
.Persons
.Where(p => p.TypeId == PersonTypeIds.Director)
.Where(p => p.PersonId == idToFind)
.ToList();
First is doing the where clause in 2 steps and then, adding the ToList(), with the ToList(), you will deal with collections and LINQ that is pretty useful. And by doing the where clause in 2 steps, is more for readable purposes.

"The specified type member 'Date' is not supported in LINQ to Entities" [duplicate]

This question already has answers here:
The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties
(11 answers)
Closed 3 years ago.
I started an asp.net mvc project and I wanna filter requesting data from database with dynamic linq/lambda. Some part of my code is as below:
IQueryable<VehicleMilage> query = null;
if (Fr_DeviceId == null && Fr_ContractId == null && From_Date == null && To_Date == null && From_QueryDate == null && To_QueryDate == null)
{
query = (db.VehicleMilage).OrderBy(x => x.Id).Skip(skip).Take(rows);
}
else
{
query = (db.VehicleMilage);
if (Fr_DeviceId != null)
{
int a = int.Parse(Fr_DeviceId);
query = query.Where(x => x.Fr_DeviceId == a);
}
if (Fr_ContractId != null)
{
int b = int.Parse(Fr_ContractId);
query = query.Where(x => x.Fr_ContractId == b);
}
if (From_Date != null)
{
query = query.Where(x => x.From_Date.Date >= FromDate_ConvertedToDateTime1.Date);
}
if (To_Date != null)
{
query = query.Where(x => x.To_Date.Date <= ToDate_ConvertedToDateTime1.Date);
}
if (From_QueryDate != null)
{
query = query.Where(x => x.CreateDate.Date >= FromQueryDate_ConvertedToDateTime1.Date);
}
if (To_QueryDate != null)
{
query = query.Where(x => x.CreateDate.Date <= ToQueryDate_ConvertedToDateTime1.Date);
}
query = query.OrderBy(x => x.Id).Skip(skip).Take(rows);
}
My data in database is at least 2000000 records and I must define the variable query as IQueryable.
In block of else I must filter the query with every parameter that is not null but I encounter the error
The specified type member 'Date' is not supported in LINQ to Entities.
If I define the variable of query as List, then I could put ToList() before Where In every if in block of else that is related to datetime as below but in this project because of heavy data I cannot do this:
query = query.ToList().Where(x => x.From_Date.Date >= FromDate_ConvertedToDateTime1.Date);
query = query.Where(x => x.From_Date.Date >= FromDate_ConvertedToDateTime1.Date);
could be replaced with:
var fromDate = FromDate_ConvertedToDateTime1.Date;
query = query.Where(x => x.From_Date >= fromDate);
It has the same logical meaning, will generate efficient SQL and (most importantly) it won't experience the error you are seeing.
For less than or equal to, it is slightly more complicated - but not markedly so.
query = query.Where(x => x.To_Date.Date <= ToDate_ConvertedToDateTime1.Date);
could be replaced with:
var dayAfterToDate = ToDate_ConvertedToDateTime1.Date.AddDays(1)
query = query.Where(x => x.To_Date < dateAfterToDate);
That logic might seem odd at first glance - but if it is before the date after the ToDate that is logically equivalent to being on or before the ToDate (ignoring the time component).
Repeat the same process for the other queries - they will follow the exact same pattern.

Using variables in the lambda

I am using Linq to filter some things and some times I need to use reflection to get the value. Here is the example:
//...
PropertyType[] properties = myType.GetProperties();
var filtered = properties.Where(p=>p.PropertyType==typeof(MyMetaData)
&& ((MyType)p.GetValue(obj)).Name=="name"
&& ((MyType)p.GetValue(obj)).Length==10
).ToList();
//...
In my example I am using GetValue() method more than one time. Is there way if I can use variable to store it? I think that will help with performance.
It looks like that to include some variable in a LINQ we have to use the expression query, not method query, like this:
var filtered = (from x in properties
let a = (x.PropertyType is MyType) ? (MyType) x.GetValue(obj) : null
where a != null && a.Name == "name" && a.Length == 10).ToList();
I think this also works for method query with some Select:
var filtered = properties.Select(p=> new {p, a = (p.PropertyType is MyType) ? (MyType) p.GetValue(obj) : null})
.Where(x=>x.a != null && x.a.Name == "name" && x.a.Length == 10)
.Select(x=>x.p).ToList();
Something like following should work with method expression(lambda syntax)
var filtered = properties.Where(p =>
{
if(!p.PropertyType is MyMetaData)
{
return false;
}
var item = (MyType) p.GetValue(obj);
return item.Name == "name"
&& item.Length == 10
}
).ToList();

The LINQ expression node type 'Invoke' is not supported in LINQ to Entities

I have a problem trying to implement a filtering expression to filter a list of entities :
The LINQ expression node type 'Invoke' is not supported in LINQ to
Entities.
This is the code :
public IList<DocumentEntry> GetDocumentEntriesForRateAdjustmentTry2(
string username, Rate rate, List<RatePeriod> ratePeriods)
{
var dimensionLibManager = new DimensionLibManager();
var currentVersionRateGroups = rate.CurrentRateVersion.RateGroups.ToList();
Expression<Func<DocumentEntry, IList<RateGroup>, int, bool>> dimensionMatchesExpression =
(documentEntry, rateGroups, dimensionInfoId) =>
rateGroups.Any(
rg =>
rg.Dimension1.All(character => character == '*')
||
documentEntry.DocumentEntryDimensions.Any(
ded =>
ded.DimensionInfo.Position == dimensionInfoId
&&
dimensionLibManager.GetDimensionSegments(rate.CompanyId, username, dimensionInfoId, ded.Value).Any(
seg => ded.Value.Substring(seg.SegmentStart, seg.SegmentLength) == seg.SegmentValue)));
var dimensionMatches = dimensionMatchesExpression.Compile();
var documentEntries = this.ObjectSet.Where(de => dimensionMatches(de, currentVersionRateGroups, 1));
var result = documentEntries.ToList(); // The error happens here.
return result;
}
I suspect that dimensionMatchesExpression cannot be traduced into SQL because inside it calls another library's method (dimensionLibManager.GetDimensionSegments) to filter documents based on specific parameters.
Is there a way (other than using LinqKit or any additionnal extention library) that I can make this work ?
The reason why I want to use an Expression to act as a filter is because, ultimately, I would like to to this :
var documentEntries = this.ObjectSet.Where(de =>
dimensionMatches(de, currentVersionRateGroups, 1)
&& dimensionMatches(de, currentVersionRateGroups, 2)
&& dimensionMatches(de, currentVersionRateGroups, 3)
&& dimensionMatches(de, currentVersionRateGroups, 4));
Also, how can I actually debug that kind of problem ? The error message is pretty vague. How can I track down the exact node that is causing the error ?
I suspect this is the issue.
var documentEntries = this.ObjectSet.Where(de => dimensionMatches(de, currentVersionRateGroups, 1));
I don't think that row number works with Linq2EF.
public IList<DocumentEntry> GetDocumentEntriesForRateAdjustmentTry2(
string username, Rate rate, List<RatePeriod> ratePeriods)
{
var dimensionLibManager = new DimensionLibManager();
var currentVersionRateGroups = rate.CurrentRateVersion.RateGroups.ToList();
Expression<Func<DocumentEntry, int, bool>> dimensionMatchesExpression =
(documentEntry, rateGroups, dimensionInfoId) =>
currentVersionRateGroups.Any(
rg =>
rg.Dimension1.All(character => character == '*')
||
documentEntry.DocumentEntryDimensions.Any(
ded =>
ded.DimensionInfo.Position == dimensionInfoId
&&
dimensionLibManager.GetDimensionSegments(rate.CompanyId, username, dimensionInfoId, ded.Value).Any(
seg => ded.Value.Substring(seg.SegmentStart, seg.SegmentLength) == seg.SegmentValue)));
var documentEntries = this.ObjectSet.Where(dimensionMatchesExpression);
var result = documentEntries.ToList(); // The error happens here.
return result;
}
Although I don't understand why you want to use an expression to do this. You could just inline it all...
Just realised a few days ago the solution to your problem...bit of a hack...
public Expression<Func<DocumentEntry, int, bool>> CreateWhereClause(stuff);
public IList<DocumentEntry> GetDocumentEntriesForRateAdjustmentTry2(
string username, Rate rate, List<RatePeriod> ratePeriods)
{
using(var db = new Context())
{
IQueryable<DocumentEntry> foo = db.Foos;
foreach(var i =0; i <4; i++)
{
foo = foo.Where(DocumentEntry(i));
}
}
}

How can I add Where expressions to a LINQ query if I'm not sure which properties I'll want to match?

I have a situation where I might want to search by order number or by name. I know I can add a Where expression to my LINQ query, but I only want to add it for the property that I'm searching for! I won't know until the method is called which parameter will be provided, so how can I add the proper condition?
public JsonResult Search(int orderNo=0, string firstName="", string lastName="")
{
if (orderNo >0){
//add Condition
}
if (firstName.Length > 0){
//add Condition
}
if (lastName.Length > 0){
//add Condition
}
//get Result
var result = Repository.Orders.Where(???).OrderByDescending(e=> e.orderNo);
//return
}
The following assumes Repository.Orders is returning an IQueryable, but the idea is just to dynamically add the expressions you need. The execution of the query is deferred, so you can build it systematically before actually asking for the results.
// You haven't executed the query yet, you can still build up what you need
var query = Repository.Orders;
if(orderNo >0){
// You STILL haven't actually executed the query.
query.Where(x => x.orderNo == orderNo);
}
if(firstName.Length > 0){
query.Where(x => x.firstname == firstName);
}
if(lastName.Length > 0){
query.Where(x => x.lastName == lastName);
}
// Even with this, you STILL aren't actually executing the query.
query.OrderByDescending(x => x.orderNo);
// You'll be executing and enumerating the results here, but that's OK because you've fully defined what you want.
return Json(query.ToArray(), JsonRequestBehavior.AllowGet);
Assuming your repository returns IQueryable you can compose your query however you want to:
var query = Repository.Orders;
if(orderNo > 0)
{
query = query.Where( x => x.OrderId == orderNo);
}
if(firstName.Length > 0)
{
query = query.Where( x => x.FirstName == firstName);
}
//...
If you have to AND these conditions and assuming your repository returns IQueryable (if not change it or add another overload or something)
var query = Repository.Orders
// Build where clause
if (orderNo >0){
query = query.Where(o => o.OrderNo == orderNo);
}
if (firstName.Length > 0){
query = query.Where(o => o.FirstName == firstName);
}
if (lastName.Length > 0){
query = query.Where(o => o.LastName == lastName);
}
// Build OrderBy clause
query = query.OrderByDescending(o => o.orderNo);
// Execute Query
results = query.ToList();
var result = Repository.Orders.Where(x =>
(firstName == null || firstName.Trim() == "" || x.FirstName.Contains(firstName))
&& (lastName == null || lastName.Trim() == "") || x.LastName.Contains(lastName))
&& (orderNo == 0 || x.OrderNo == orderNo)).OrderByDescending(x => x.OrderNo)
#Amit_g's example will work as well, and is arguably easier to read. I like to do it all in one query. It's a matter of preference.

Categories