LINQ and C# - Dealing with a potentially null parameter - c#

I am relatively new to LINQ but looking for some "best practice" advice on how to deal with the following. I know there are many ways to deal with this, but looking to see how more experienced people would write the code.
My LINQ at present:
var company = (from c in db.RPTINQUIRies
where c.CONCOM == concom && c.LOPER == engineer
orderby c.CREATION_DATE descending
select c);
Now the ActionResult parameter that is being passed in here (engineer) may or may not be empty. Where it is empty, I essentially want to remove the && C.LOPER == engineer clause all together.
What's the best way to deal with this?

It sounds like you just want:
where c.CONCOM == concom && (engineer == null || c.LOPER == engineer)
Alternatively, you could build up the query step by step:
var query = db.RPTINQUIRies.Where(c => c.CONCOM == concom);
if (engineer != null)
{
query = query.Where(c => c.LOPER == engineer);
}
query = query.OrderByDescending(c => c.CREATION_DATE);

Related

Combine two Lambda expressions using result of first Lambda expression

I was wondering if it's possible to combine these two statements into one.
Tbl_OrderFeeItem orderFee = adj.Tbl_Order.Tbl_OrderFeeItem.Single(x =>
x.OrderId == adj.OrderId
&& x.FeeTypeId == adj.FeeTypeId);
int querySource = orderFee.Tbl_FeeCheck
.Single(x => x.OrderFeeItemId == formFee.OrderFeeItemId)
.Tbl_PostPaymentOrderQuery
.PostPaymentOrderQueryTypeId;
What I'm trying to do is something like this...
int querySource = adj.Tbl_Order.Tbl_OrderFeeItem.Single(x =>
x.OrderId == adj.OrderId && x.FeeTypeId == adj.FeeTypeId)
.Tbl_FeeCheck.Single('use the id from the result of Tbl_OrderFeeItem.Single() call')
.Tbl_PostPaymentOrderQuery.PostPaymentOrderQueryTypeId;
I hope that made sense, I'm trying to use the id from the first query in the second but have it as one complete statement instead of two separate ones.
Thanks in advance
It's difficult to provide an accurate answer without any of the constructs present in your program, but by surrounding the original query with brackets it should allow you to perform the second query on the result of the first without using two seperate statements:
((Tbl_OrderFeeItem)adj.Tbl_Order.Tbl_OrderFeeItem.Single(x =>
x.OrderId == adj.OrderId
&& x.FeeTypeId == adj.FeeTypeId))
.Tbl_FeeCheck
.Single(x => x.OrderFeeItemId == formFee.OrderFeeItemId)
.Tbl_PostPaymentOrderQuery
.PostPaymentOrderQueryTypeId;

A query body must end with a select clause or a group clause c#

While this is a frequently asked question I have not found a solution that fits my situation.
I am receiving the above compile error on the following code:
var data = from g in db.MD_import_results
.Where((fProjectID == tProjectID) && (g.md_CheckResults) != null
|| (g.md_CheckResults1) != null || (g.md_CheckResults2) != null
|| (g.md_CheckResults3) != null).Select(
p => new
{
p.AccountID,
p.md_HouseNumber,
p.md_StreetPreDirectional,
p.md_StreetName,
p.md_StreetSuffix,
p.md_StreetPostDirectional,
p.md_Suite,
p.md_City,
p.md_State,
p.md_ZipCode,
p.md_CheckResults,
p.md_CheckResults1,
p.md_CheckResults2,
p.md_CheckResults3,
p.ProjectID
});
Any suggestions are appreciated.
There are two ways to write LINQ queries, query syntax and method syntax.
Query syntax looks like
from g in x
where g.foo == bar
select g.baz;
Method syntax looks like
x.Where(g => g.foo == bar).Select(g => g.baz);
You have combined the two. You started writing from g in x and then continued writing .Where(...). Pick one syntax and stick with it.

LINQ lambda expression append OR statement

If I want to append a AND statement to my query, I can do:
query = query.Where(obj=>obj.Id == id);
if(name.HasValue)
query = query.Where(obj=>obj.Name == name);
and it will give me:
query.Where(obj=>obj.Id == id && obj.Name == name)
How can I append a OR statement that will result in:
query.Where(obj=>obj.Id == id || obj.Name == name)
You can't do it natively. However, you can use PredicateBuilder to compose the query before you run it, and it supports ORs.
var predicate = PredicateBuilder.False<Product>();
predicate = predicate.Or (obj=>obj.Id == id);
if(name.HasValue) predicate = predicate.Or (obj=>obj.Name == name);
return query.Where(predicate);
Simply this if I'm not missing something:
query.Where(obj=>obj.Id == id || (obj.Name == name && name.HasValue))
You might want to read this question (my question...) and answer for more complicated scenarios:
How to filter IEnumerable based on an entity input parameter
I would just build this into a single condition:
if (name.HasValue)
query = query.Where(obj=>obj.Id == id && obj.Name == name);
else
query = query.Where(obj=>obj.Id == id);
I would use gdoron's solution, but if it seems unpractical for larger sets of queries, a slightly more complicated solution containing set operations might help you:
var queryById = query.Where(obj => obj.Id == id);
var queryByName = query.Where(obj => obj.Name == name);
query = queryById.Union(queryByName);
It gets much more difficult if your original query contains duplicate items.
Another way may be using Expression to formulate your queries. You can modify the expression tree before executing it, so you can add more conditions to the Where sub-tree. That is a whole lot of work and it's an overkill on 99.9% (rough estimate :) ) of cases.
Part of the problem is that you over write your original query. Your OR operation would be equivalent to:
subquery1 = query.Where(obj=>obj.Id == id);
subquery2 = query.Where(obj=>obj.Name == name);
query = subquery1.Concat(subquery2).Distinct();
As you can see, that becomes pretty unwieldy as well, however if You are going to do this form, then you must maintain the original sequence so that you can get both the right and left sides of the equation processed then you need to be sure duplicates get removed.
Instead of all that, I would try to figure a way to build up that conditional statement dynamically using lambdas e.g.
I haven't actually run this, but something like this should work.
var cond = obj=>obj.Id == id;
...
// need an or
cond = obj=>cond(obj) || obj.Name == name;
query = query.Where(obj=>cond(obj));
Hope this gives you an idea.

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

Test for List<T> membership using a List<T>

Does anyone know if there is a way to test for list membership utilizing a list. For example I have a class named Membership which has a property Rebates which is of type List<Enums.RebateType>. I want to test using a lambda expression to see if that list contains any rebates that are of a specific type. My orginal lambda expression is as follows
return Membership.Rebates.Exists(rebate =>
rebate.RebateType == Enums.RebateType.A &&
rebate.RebateStatus == Enums.RebateStatus.Approved);
Instead of having to do the following:
return Membership.Rebates.Exists(rebate =>
(rebate.RebateType == Enums.RebateType.A &&
rebate.RebateStatus == Enums.RebateStatus.Approved) ||
(rebate.RebateType == Enums.RebateType.B &&
rebate.RebateStatus == Enums.RebateStatus.Approved));
I was wondering if something similar to the following mocked up SQL syntax could be done via one Lambda expression.
SELECT COUNT(*)
FROM Membership.Rebates
WHERE RebateType IN (ValidRebateTypes) AND Approved = true
ValidRebateTypes is curently a List<Enums.RebateType> that I am testing for i.e. ValidRebateTypes = (Enums.RebateType.A, Enums.RebateType.B).
The work around I currently have is as follows:
bool exists = false;
foreach (Enums.RebateType rebateType in ValidRebateTypes())
{
exists = Membership.Rebates.Exists(
rebate =>
rebate.RebateType == rebateType &&
rebate.RebateStatus == Enums.RebateStatus.Approved);
if (exists) { break; }
}
return exists;
Sounds like you want:
Membership.Rebates.Where(r => ValidRebateTypes.Contains(r.RebateType)
&& r.RebateStatus == Enums.RebateStatus.Approved);
You can then use .Count() for the count:
Membership.Rebates.Where(r => ValidRebateTypes.Contains(r.RebateType)
&& r.RebateStatus == Enums.RebateStatus.Approved)
.Count();
Or .Any() to determine the existence of any that satisfy that condition
Membership.Rebates.Any(r => ValidRebateTypes.Contains(r.RebateType)
&& r.RebateStatus == Enums.RebateStatus.Approved);
In addition to Marc's suggestion, I would recomment making ValidRebateTypes a HashSet<Enums.RebateType>. Not only is this likely to be more efficient (although possibly not for a small set), it also reveals your intent (ie. that there only be one of each value of RebateType in it).

Categories

Resources