Change the order by field based on a condition - c#

I have a scenario where I have to change the order by field based on some condition.
from summaryRows in _summaryTable.AsEnumerable()
where summaryRows.Field<string>("AirlineDisplayName")
.Equals(airlineName_, StringComparison.OrdinalIgnoreCase)
orderby summaryRows.Field<decimal>("FareAdult")
select new
{
summaryTableRow = summaryRows
};
Based on the condition, I have to change the order by field to orderby summaryRows.Field<double>("BasePricePlusTaxAndFees")
Here, both the field data type is different. How can I do it in one query?

I think this will be the most readable using fluent Linq syntax and introducing an if-statement while building the query.. Since you do not explain your condition, I assume that you have a boolean variable called condition with the appropriate value:
var query = _summaryTable.AsEnumerable()
.Where(
summaryRows => summaryRows.Field<string>("AirlineDisplayName")
.Equals(airlineName_, StringComparison.OrdinalIgnoreCase));
if (condition)
query = query.OrderBy(summaryRows => summaryRows.Field<decimal>("FareAdult"));
else
query = query.OrderBy(summaryRows => summaryRows.Field<double>("BasePricePlusTaxAndFees"));
var resultQuery = query.Select(summaryRows => new
{
summaryTableRow = summaryRows
});
Disclaimer: I have not tested it, but good luck.

What about this:
orderby conditionIsTrue ? (IComparable)summaryRows.Field<double>("BasePricePlusTaxAndFees") : (IComparable)summaryRows.Field<decimal>("FareAdult")

Related

Loop to set OrderBy/ThenBy for multiple columns

I'm using DataTables.Mvc library for use with jQuery DataTables.
One of the methods is GetSortedColumns() which returns an array containing configurations for each column to be sorted.
Of interest in this object are the Name and SortDirection properties. Name is also the database table field name. SortDirection is either asc or desc.
At first ThenBy and ThenByDescending were undefined symbols, so I created ordered as IOrderedQueryable. This resolves the symbols, but I don't see any effect of these. Neither OrderBy, OrderByDescending, ThenBy nor ThenByDescending have any effect on the order of records in filteredRecords.
In Controller:
[AcceptVerbs(HttpVerbs.Post)]
public JsonResult GetUserSelections([ModelBinder(typeof(DataTablesBinder))] IDataTablesRequest requestModel)
{
// Column Sort
var filteredRecords = db.AspNetSelectorInputs.Select(si => si);
var sortedColumns = requestModel.Columns.GetSortedColumns();
var count = 0;
foreach (var column in sortedColumns)
{
var ordered = filteredRecords as IOrderedQueryable<AspNetSelectorInput>;
filteredRecords =
column.SortDirection == DataTables.Mvc.Column.OrderDirection.Ascendant
? count == 0
? ordered.OrderBy(c => column.Name)
: ordered.ThenBy(c => column.Name)
: count == 0
? ordered.OrderByDescending(c => column.Name)
: ordered.ThenByDescending(c => column.Name);
count++;
}
filteredRecords = filteredRecords.Select(si => si).Skip(requestModel.Start).Take(requestModel.Length);
....
Can anyone see why this doesn't affect ordering of filteredRecords?
Is there a better way?
It is sorting, on exactly what you've asked it to. But the lambda expressions aren't doing what you think. For example, you're doing .OrderBy(c => column.Name), which is sorting using a literal value of the name of the column which has the same value for every item in the collection (notice how the thing it is sorting on is not affected by c), so it appears not to sort your collection. For example, you might as well be doing .OrderBy(c => "Hello").
You would need to do something like .OrderBy(c => c.YourChoiceOfPropertyName). Except you can't do that because (presumably) the name of the property is a string value in column.Name. So you'll need to use reflection within the lambda to get the value of that property using c as the instance. This will need fixing on all the lambdas. For example, inside the loop:
var propertyInfo=typeof(AspNetSelectorInput)
.GetProperty(column.Name);
And replacement lambda expressions:
c=>propertyInfo.GetValue(c)
P.S. the two instances of .Select(si => si) seem to be redundant, unless I am missing something.

In Linq, is a SELECT required when WHERE is used?

If you have a Linq statement that uses a WHERE clause, for example:
var result = someCollection.Where(x => x.value > 5).Select(x => x);
Is the SELECT required, or is it redundant? It appears that I can safely omit the SELECT if I'm not trying to get at an object property, but am not sure if this is proper...
In your case No, it is not required, since you are selecting the object. So you can have:
var result = someCollection.Where(x => x.value > 5);
as far as better practice is concerned, I would remove the redundant code.
But, if you are going to select a specific property then that could be useful, like:
var result = someCollection.Where(x => x.value > 5)
.Select(x=> x.SomeSpecificProperty);
One more thing to add, with query expression you will need the select.
var result = from x in someCollection
where x.Value > 5
select x;
but at compile time the above query expression will be converted to Method Expression, without Select.
It's redundant. Select is more like the functional map (see JavaScript, Haskell, Ruby). If you aren't going to transform the input object into a different form than it is currently in, there's no need to use Select.
In Linq, is a SELECT required when WHERE is used?
No, it isnt.
No... is not necessary this time... may be if you want to select a new object different than "someCollection" it will be necessary
something like:
var result = someCollection.Where(x => x.value > 5).Select(x => new ObjName() { name = x.name, lastname = x.lastname });

How to build a LINQ to XML query with a conditional selection

The xml elements are variable depending on some conditional. I need to initialize an instance with a different element, based on the value of some other element.
var result = (from name in names
select new MyName
{
name.First = name.Type = Fracais ? name.PreNom : name.First,
name.Last
}
Any ideas?
What you have is almost right. I had to guess the enums and members as you don't provide the other classes:
var result = from name in names
select new Person()
{
First = name.Type == PersonType.Fracais ? name.PreNom : name.First,
Last = name.Last
};
You can have pretty much any expression, including function calls, in a linq query, so testing values and mutating them on the fly is perfectly acceptable.
How about this? As a pointless alternative.
var result = names.where(name => name.Type == Francais).Select(name =>
name.PreNom, name.Last).Union()
names.where(name => name.Type != Francais).Select(name.First, name.Last);

Chain together multiple complex WHERE clauses in LINQ to SQL

This is the pseudo-SQL I want to generate:
SELECT * FROM Table WHERE Column1 = #Value1 OR Column2 = #Value2
The problem is, sometimes the second one should not be included. I was hoping to chain together .Where() clauses like so:
var query = context.TableName;
query = query.Where(t => t.Column1 == value1);
if (NeedsToBeIncluded(value2))
query = query.Where(t => t.Column2 == value2);
Unfortunately, this doesn't work. .Where() will emit an AND if you chain them together by default. Is there a way to get it to emit an OR?
I'm looking for something along the lines of:
var query = context.TableName;
query = query.Where(t => t.Column1 == value1);
if (NeedsToBeIncluded(value2))
query = query.OrWhere(t => t.Column2 == value2);
UPDATE
Ok, so my example listed above is too simple. It was merely supposed to be an example that outlines the problem space. Out "in the wild" so to speak, Column1 and Column2 could actually be "CarType" and "OwnerName", maybe there's more, maybe there's less. I just used a simple example to outline the problem because I'm looking to solve a range of domain problems with this chaining-.Where()s together.
One way is to use LINQKit's PredicateBuilder.
Another way is to use a list:
var values = new List<string> { value1 };
if (NeedsToBeIncluded(value2)) values.Add(value2);
query = context.TableName.Where(t => values.Contains(t));
PB is more flexible, but the list will solve the problem in your question. Note that you need EF 4 for Contains.
I gave an example how to dynamically build a condition yesterday - see here. For your case it would be something like that.
var parameter = Expression.Parameter(typeof(TableName), "t");
Expression condition = Expression.Equal(
Expression.Property(parameter, "Column1"),
Expression.Constant(value1)));
if (NeedsToBeIncluded(value2))
{
condition = Expression.OrElse(
condition,
Expression.Equal(
Expression.Property(parameter, "Column2"),
Expression.Constant(value2)));
}
var expression = Expression.Lambda<Func<TableName, Boolean>>(condition, parameter);
var query = context.TableName.Where(expression);

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