How do I convert this expression to LINQ? - c#

Is it possible to convert this expression to LINQ?
TermsOfPayment termsOfPayment = null;
foreach (CustomerGroup group in _customer.CustomerGroups)
if (termsOfPayment == null) termsOfPayment = group.TermsOfPayment;
else if (group.TermsOfPayment != null)
if (group.TermsOfPayment.InvoiceDueDays < termsOfPayment.InvoiceDueDays)
termsOfPayment = group.TermsOfPayment;
It might seem like a stupid question since the expression above solves the question, but I use some LINQ expressions and am eager to lern more - hence the reason for this post.
Basically I just want to select the TermsOfPayment object with the minimum InvoiceDueDays (integer) value from the groups the customer is a part of.

termsOfPayment = (
from g in _customer.CustomerGroups
where g.TermsOfPayment != null
orderby g.TermsOfPayment.InvoiceDueDays
select g.TermsOfPayment
).FirstOrDefault();

var termsOfPayment =
_customer.CustomerGroups.OrderBy(cg=>cg.TermsOfPayment.InvoiceDueDays)
.First().Select(cg=>cg.TermsOfPayment);

Why not use aggregate, speed is better too:
var termsOfPayment =
_customer.CustomerGroups.Aggregate((a, n) => n.TermsOfPayment.InvoiceDueDays < a.TermsOfPayment.InvoiceDueDays ? n : a).TermsOfPayment;

Related

Consolidate many if conditions to a single LINQ statement using OR [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Linq: “Or” equivalent of Where()
I posted a question about a week ago where the solution to append to a LINQ query based on if my parameters had values in them looked like:
var query = Database.Set<User>();
if (condition1.HasValue)
{
query = query.Where(x => x.Condition1 == condition1.Value);
}
if (condition2.HasValue)
{
query = query.Where(x => x.Condition2 == condition2.Value);
}
...
return query.ToList();
This code would append to the WHERE clause using AND. How would I go about appending to the WHERE clause using OR instead?
You'll want to use a predicate builder, here is an example
You could try using the PredicateBuilder library. Here's a sample:
var predicate = PredicateBuilder.False<User>();
if (condition1.HasValue)
{
predicate = predicate.Or(x => x.Condition1 == condition1.Value);
}
if (condition2.HasValue)
{
predicate = predicate.Or(x => x.Condition2 == condition2.Value);
}
return Database.Set<User>().Where(predicate);
This would do the trick, as an alternative to PredicateBuilder.
var query = Database.Set<User>();
var query2 = query.Where(x => (condition1.HasValue && x.Condition1 == condition1.Value) || (condition2.HasValue && x.Condition2 == condition2.Value));
You have to create expression tree yourself for this. Or the other way, you can use Dynamic LINQ and construct LINQ quesry string and execute it.
Look at System.Linq.Expression names, or System.Linq.Dynamic
You can't. Explanation:
var iS = {1,2,3,4,5};
var iEvens = iS.Where(x => x % 2 == 0);
var iEvensAddOr = iEvens.OrWhere(x => x % 2 == 1);
You expect to have iS.Where(x => x % 2 == 0 || x % 2 == 1), but you have already filtered your list with the first Where(). What you want would be to undo the filter and create a new one. But you have already filtered, it's too late.
You can use a union, but it's not exactly what you want.

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

would it be bad practice to add select to shorten Linq query?

for example
Originally:
var query = A.Where(x=>criteriaA(x.item2).Where(x=>criteriaB(x.item2))
.Where(x=>criteriaC(x.item2))).Select(x=>x.item2);
What if:
var B = A.Select(x=>x.item2)
var query = B.Where(x=>criteriaA(x)
.Where(x=>criteriaB(x)).Where(x=>criteriaC(x)));
it's fine - what about
var query = A.Select(x=>x.item2)
.Where(item2=> criteriaA(item2)
&& criteriaB(item2)
&& criteriaC(item2));
There would be little difference and should have similar performance characteristics. I've also checked in linq pad and the resultant SQL for linq to SQL is identical
You can shorten the query further with either
var B = A.Select(x=>x.item2)
var query = B.Where(x=>criteriaA(x) && criteriaB(x) && criteriaC(c));
or
var B = A.Select(x=>x.item2)
var query = B.Where(criteriaA).Where(criteriaB).Where(criteriaC);
They produce the same result, and I expect them to have very similar performance characteristics. The second has a little less duplication, so I'd prefer that one. You might even be able to shorten it further to:
var query = A.Select(x=>x.item2)
.Where(criteriaA).Where(criteriaB).Where(criteriaC);
Or, by collapsing all the predicates:
var query = A.Select(x=>x.item2)
.Where(x => criteriaA(x) && criteriaB (x) && criteriaC(x));
Linq queries could be written in many ways, but I prefer to keep them as readable as possible.
I would prefer something like:
var query = from x in A
where criteriaA(x) && criteriaB(x) && criteriaC(x)
select x;

Convert this code to LINQ?

Sorry, Im just learning LINQ and am relatively new at it.
Is it possible to convert the following into LINQ?
foreach (DataRow gradeCount in GraceTable.Rows)
{
if (Convert.ToDecimal(obtMarksRow["Percentage"]) >=
(Convert.ToDecimal(gradeCount["EXG_MARKS_ABOVE"])) &&
(Convert.ToDecimal(obtMarksRow["Percentage"]) <=
Convert.ToDecimal(gradeCount["EXG_MARKS_BELOW"])))
{
string Grade = Convert.ToString(gradeCount["EXG_GRADE_NAME"]);
}
}
Edit : sorry i missed for each loop in ma query and obtMarksRow comes from one more loop which is outside this
I wrote the query like this
var gradeValue = from DataRow gradeRow in GraceTable.Rows
let marksAbove = gradeRow.Field<decimal>("EXG_MARKS_ABOVE")
let marksBelow = gradeRow.Field<decimal>("EXG_MARKS_BELOW")
where obtMarksRow.Field<decimal>("Percentage") >= marksAbove && obtMarksRow.Field<decimal>("Percentage") <= marksBelow
select gradeRow.Field<string>("EXG_GRADE_NAME");
but i am getting the value (gradeValue.ToString() ) as "System.Linq.Enumerable+WhereSelectEnumerableIterator`2[System.Data.DataRow,System.String]"
Whats wrong ?
No, it isn't possible. As the commenters point out, LINQ is for querying collections of things. You don't appear to have a collection here: just an if statement and an assignment.
Furthermore, be careful about trying to convert things to LINQ unnecessarily. As you start to understand LINQ better, you'll find yourself naturally using it for a variety of purposes. But starting off with the assumption that code will be better with LINQ is probably a fallacy.
Edit
As mentioned earlier, LINQ is about querying a collection for a set of results. If you only want one result, you can use Single, First, SingleOrDefault, or FirstOrDefault to get it out of the resulting collection.
var gradeValues = from DataRow gradeRow in GraceTable.Rows
let marksAbove = gradeRow.Field<decimal>("EXG_MARKS_ABOVE")
let marksBelow = gradeRow.Field<decimal>("EXG_MARKS_BELOW")
where obtMarksRow.Field<decimal>("Percentage") >= marksAbove && obtMarksRow.Field<decimal>("Percentage") <= marksBelow
select gradeRow.Field<string>("EXG_GRADE_NAME");
var firstGradeValue = gradeValues.First(); // will throw exception if there were no matches.
Console.WriteLine(firstGradeValue);
Try the following:
var grades = from r in GraceTables.Rows
where obtMarksRow.Field<decimal>("Percentage") >=
r.Field<decimal>("EXG_MARKS_ABOVE") &&
obtMarksRow.Field<decimal>("Percentage") <=
r.Field<decimal>("EXG_MARKS_BELOW")
select r.Field<string>("EXG_GRADE_NAME");
You shouldn't use Linq per se but you should use the DatasetExtensions, brought in alongside linq, to get your columns from the DataRow in a type safe way without the need to convert them, i.e.
if (obtMarksRow.Field<decimal>("Percentage") >= (Convert.ToDecimal(gradeCount["EXG_MARKS_ABOVE"])) && etc...

Dynamic WHERE clause in LINQ

What is the best way to assemble a dynamic WHERE clause to a LINQ statement?
I have several dozen checkboxes on a form and am passing them back as: Dictionary<string, List<string>> (Dictionary<fieldName,List<values>>) to my LINQ query.
public IOrderedQueryable<ProductDetail> GetProductList(string productGroupName, string productTypeName, Dictionary<string,List<string>> filterDictionary)
{
var q = from c in db.ProductDetail
where c.ProductGroupName == productGroupName && c.ProductTypeName == productTypeName
// insert dynamic filter here
orderby c.ProductTypeName
select c;
return q;
}
(source: scottgu.com)
You need something like this? Use the Linq Dynamic Query Library (download includes examples).
Check out ScottGu's blog for more examples.
I have similar scenario where I need to add filters based on the user input and I chain the where clause.
Here is the sample code.
var votes = db.Votes.Where(r => r.SurveyID == surveyId);
if (fromDate != null)
{
votes = votes.Where(r => r.VoteDate.Value >= fromDate);
}
if (toDate != null)
{
votes = votes.Where(r => r.VoteDate.Value <= toDate);
}
votes = votes.Take(LimitRows).OrderByDescending(r => r.VoteDate);
You can also use the PredicateBuilder from LinqKit to chain multiple typesafe lambda expressions using Or or And.
http://www.albahari.com/nutshell/predicatebuilder.aspx
A simple Approach can be if your Columns are of Simple Type like String
public static IEnumerable<MyObject> WhereQuery(IEnumerable<MyObject> source, string columnName, string propertyValue)
{
return source.Where(m => { return m.GetType().GetProperty(columnName).GetValue(m, null).ToString().StartsWith(propertyValue); });
}
It seems much simpler and simpler to use the ternary operator to decide dynamically if a condition is included
List productList = new List();
productList =
db.ProductDetail.Where(p => p.ProductDetailID > 0 //Example prop
&& (String.IsNullOrEmpty(iproductGroupName) ? (true):(p.iproductGroupName.Equals(iproductGroupName)) ) //use ternary operator to make the condition dynamic
&& (ID == 0 ? (true) : (p.ID == IDParam))
).ToList();
I came up with a solution that even I can understand... by using the 'Contains' method you can chain as many WHERE's as you like. If the WHERE is an empty string, it's ignored (or evaluated as a select all). Here is my example of joining 2 tables in LINQ, applying multiple where clauses and populating a model class to be returned to the view. (this is a select all).
public ActionResult Index()
{
string AssetGroupCode = "";
string StatusCode = "";
string SearchString = "";
var mdl = from a in _db.Assets
join t in _db.Tags on a.ASSETID equals t.ASSETID
where a.ASSETGROUPCODE.Contains(AssetGroupCode)
&& a.STATUSCODE.Contains(StatusCode)
&& (
a.PO.Contains(SearchString)
|| a.MODEL.Contains(SearchString)
|| a.USERNAME.Contains(SearchString)
|| a.LOCATION.Contains(SearchString)
|| t.TAGNUMBER.Contains(SearchString)
|| t.SERIALNUMBER.Contains(SearchString)
)
select new AssetListView
{
AssetId = a.ASSETID,
TagId = t.TAGID,
PO = a.PO,
Model = a.MODEL,
UserName = a.USERNAME,
Location = a.LOCATION,
Tag = t.TAGNUMBER,
SerialNum = t.SERIALNUMBER
};
return View(mdl);
}
Just to share my idea for this case.
Another approach by solution is:
public IOrderedQueryable GetProductList(string productGroupName, string productTypeName, Dictionary> filterDictionary)
{
return db.ProductDetail
.where
(
p =>
(
(String.IsNullOrEmpty(productGroupName) || c.ProductGroupName.Contains(productGroupName))
&& (String.IsNullOrEmpty(productTypeName) || c.ProductTypeName.Contains(productTypeName))
// Apply similar logic to filterDictionary parameter here !!!
)
);
}
This approach is very flexible and allow with any parameter to be nullable.
You could use the Any() extension method. The following seems to work for me.
XStreamingElement root = new XStreamingElement("Results",
from el in StreamProductItem(file)
where fieldsToSearch.Any(s => el.Element(s) != null && el.Element(s).Value.Contains(searchTerm))
select fieldsToReturn.Select(r => (r == "product") ? el : el.Element(r))
);
Console.WriteLine(root.ToString());
Where 'fieldsToSearch' and 'fieldsToReturn' are both List objects.
This is the solution I came up with if anyone is interested.
https://kellyschronicles.wordpress.com/2017/12/16/dynamic-predicate-for-a-linq-query/
First we identify the single element type we need to use ( Of TRow As DataRow) and then identify the “source” we are using and tie the identifier to that source ((source As TypedTableBase(Of TRow)). Then we must specify the predicate, or the WHERE clause that is going to be passed (predicate As Func(Of TRow, Boolean)) which will either be returned as true or false. Then we identify how we want the returned information ordered (OrderByField As String). Our function will then return a EnumerableRowCollection(Of TRow), our collection of datarows that have met the conditions of our predicate(EnumerableRowCollection(Of TRow)). This is a basic example. Of course you must make sure your order field doesn’t contain nulls, or have handled that situation properly and make sure your column names (if you are using a strongly typed datasource never mind this, it will rename the columns for you) are standard.
System.Linq.Dynamic might help you build LINQ expressions at runtime.
The dynamic query library relies on a simple expression language for formulating expressions and queries in strings.
It provides you with string-based extension methods that you can pass any string expression into instead of using language operators or type-safe lambda extension methods.
It is simple and easy to use and is particularly useful in scenarios where queries are entirely dynamic, and you want to provide an end-user UI to help build them.
Source: Overview in Dynamic LINQ
The library lets you create LINQ expressions from plain strings, therefore, giving you the possibility to dynamically build a LINQ expression concatenating strings as you require.
Here's an example of what can be achieved:
var resultDynamic = context.Customers
.Where("City == #0 and Age > #1", "Paris", 50)
.ToList();

Categories

Resources