LInq Order By and Order By Desc - linq

I am using "Linq" to filter list of objects and to sort them, like
myList.Where(x => x.Item!= "SF" && x.AdSize == minadSize)
.OrderBy(x => x.ManufacturingDate)
.OrderBy(x=>x.ExpiryDate);
I doubt whether i am doing it right or not that is if i want to "sorting" on multiple fields then is it necessary to use multiple Order By clause cant it be done with single "OrderBy"

Don't use multiple OrderBy calls - use OrderBy followed by ThenBy:
var query = myList.Where(x => x.Item!= "SF" && x.AdSize == minadSize)
.OrderBy(x => x.ManufacturingDate)
.ThenBy(x => x.ExpiryDate); // Could add more ThenBy calls
If you use OrderBy twice, it will reorder the already-ordered-by-date list by expiry-date, whereas I assume you only want to order by expiry date for items with an equal manufacturing date, which is what the above does.
Obviously there's a ThenByDescending method too. For example:
var query = people.OrderBy(x => x.LastName)
.ThenBy(x => x.FirstName)
.ThenByDescending(x => x.Age)
.ThenBy(x => x.SocialSecurity);

Related

Is it possible to query aggregations on NEST for multiple term fields (.NET)?

Below is the NEST query and aggregations:
Func<QueryContainerDescriptor<ConferenceWrapper>, QueryContainer> query =
q =>
q.Term(p => p.type, "conference")
// && q.Term(p => p.conference.isWaitingAreaCall, true)
&& q.Range(d => d.Field("conference.lengthSeconds").GreaterThanOrEquals(minSeconds))
&& q.DateRange(qd => qd.Field("conference.firstCallerStart").GreaterThanOrEquals(from.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ")))
&& q.DateRange(qd => qd.Field("conference.firstCallerStart").LessThanOrEquals(to.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ")));
Func<AggregationContainerDescriptor<ConferenceWrapper>, IAggregationContainer> waitingArea =
a => a
.Terms("both", t => t
.Field(p => p.conference.orgNetworkId) // seems ignore this field
.Field(p => p.conference.isWaitingAreaCall)
// .Field(new Field( p => p.conference.orgNetworkId + "-ggg-" + p.conference.networkId)
.Size(300)
.Aggregations(a2 => a2.Sum("sum-length", d2 => d2.Field("conference.lengthSeconds"))));
I have called .Field(p => p.conference.orgNetworkId) followed by .Field(p => p.conference.isWaitingAreaCall) But it seems the NEST client tries to ignore the first field expression.
Is is possible to have multiple fields to be the terms group by?
Elasticsearch doesn't support a terms aggregation on multiple fields directly; the calls to .Field(...) within NEST are assignative rather than additive, so the last call will overwrite any previously set values.
In order to aggregate on multiple fields, you can either
Create a composite field at index time that incorporates the values that you wish to aggregate on
or
Use a Script to generate the terms on which to aggregate at query time, by combining the two field values.
The performance of the first option will be better than the second.

LINQ to Entities - query across relationships and filter

I am having a very difficult time with querying a set of related entities with LINQ and Lambda expressions.
I have four entities that are related as such ...
Vehicles 1:n VehicleTypes n:1 Prices 1:n CustomerTypes
I am trying to obtain a list of Prices for a given Vehicle and CustomerType. For example I would like to obtain all the Prices for a Ford Mustang (VehicleTypeId = 2). In those Prices I would like included the CustomerType (Government, Commercial, Retail) that the Price pertains to.
I thought I might be able to do the following ...
Prices.Include(p => p.VehicleTypes)
.Include(p => p.CustomerTypes)
.Where(p => p.VehicleTypes.Vehicles.Select(v => v.Id == 2)
However I get this error ...
Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<bool>' to 'bool'
I cannot seem to create a Where condition where I can filter the Id of the Vehicle to be purchased yet also include the CustomerType in the results.
EDIT: Just wanted to note that I have included using System.Data.Entity so I have access to the type safe Include extension
If you need the prices to that kind of vehicle and an specific customer type, you can filter as follows:
var prices= Prices.Include(p => p.VehicleTypes)
.Include(p => p.CustomerTypes)
.Where(p => p.VehicleTypes.Vehicles.Any(v => v.Id == 2)// With this condition you make sure that Mustang belong to this set of vehicles
&& p.CustomerTypes.Type=="Commercial");
But in case you want to filter the vehicles in the result, you are going to need to project your query to an anonymous type or a DTO:
var query= Prices.Include(p => p.VehicleTypes)
.Include(p => p.CustomerTypes)
.Where(p => p.VehicleTypes.Vehicles.Any(v => v.Id == 2)
&& p.CustomerTypes.Type=="Commercial")
.Select(p=>new {CustomerType=p.CustomerTypes.Type,
Vehicles=p.VehicleTypes.Vehicles.Where(v => v.Id == 2)});

Is there a easy way to filter out unique elements using linq?

I have an xml document
<NumSet>
<num>1</num>
<num>2</num>
<num>2</num>
<num>3</num>
</NumSet>
I want unique elements shown up, ie 1 and 3. not distinct which will also bring out 2.
How to do that? Do I have to use Group? Is there any concise way to do that?
You are right, you can use GroupBy and filter group which has only one item by using Count() == 1:
var output = XDocument.Load(xmlFile)
.Descendants("num")
.Select(e => e.Value)
.GroupBy(x => x)
.Where(g => g.Count() == 1)
.Select(g => g.Key);
It sounds like you want a Distinct GroupBy query... Take a look at the Need help on Linq with group by and distinct post here on StackOverflow.
XElement xe = XElement.Parse(#"<NumSet><num>1</num><num>2</num><num>2</num><num>3</num></NumSet>");
var query = xe.Elements("num")
.GroupBy(x => x.Value)
.Where(x=>x.Count ()==1)
.Select (x => x);
To do what you need I'd say that yes, you need to use GrouBy, and then count the elements in each group, and return those that contains just one element. In code, this translates to:
var query = lst.GroupBy(x => x)
.Where(x => x.Count() == 1)
.Select(x => x.Key);

Linq To Entities Optional Distinct

Earlier I put a question on Stackoverflow about how to remove duplicate records in a list of objects, based on a particular property within each object.
I got the answer I was looking for (see below), a query which returns a distinct list of objects using MainHeadingID as the property to remove duplicates.
public IList<tblcours> GetAllCoursesByOrgID(int id)
{
return _UoW.tblcoursRepo.All.
Where(c => c.tblCourseCategoryLinks.Any(cl => cl.tblUnitCategory.tblUnit.ParentID == id))
.GroupBy(c => c.MainHeadingID)
.Select(g => g.FirstOrDefault())
.ToList();
}
However, now I need more help! Is there anyway of amending the query above so that, it only removes duplicate values when MainHeadingID is not equal to 180. I tried amending GroupBy line to
.GroupBy(c => c.MainHeadingID != 180)
However, this didn't work.
Any help would be much appreciated with this.
Thanks.
Following works for LINQ to SQL:
return _UoW.tblcoursRepo.All
.Where(c => c.tblCourseCategoryLinks.Any(cl => cl.tblUnitCategory.tblUnit.ParentID == id))
.GroupBy(c => c.MainHeadingID)
//.SelectMany(g => g.Key == 180 ? g : g.Take(1))
.SelectMany(g => g.Take(g.Key == 180 ? Int32.MaxValue : 1))
.ToList();
Comments: SelectMany in query above selects all items from group where MainHeadingID equals to 180, but it takes only one item form other groups (i.e. distinct result). Linq to SQL cannot translate commented out part, but thanks to #usr there is way around.
Linq to Entities cannot translate even simplified query. I think only option for you in this case is simple concating result of two queries:
Expression<Func<tblcours, bool>> predicate = x =>
x.tblCourseCategoryLinks.Any(cl => cl.tblUnitCategory.tblUnit.ParentID == id)
int headingId = 180;
return _UoW.tblcoursRepo.All
.Where(c => c.MainHeadingID != headingId)
.Where(predicate)
.GroupBy(c => c.MainHeadingID)
.Select(g => g.FirstOrDefault())
.Concat(_UoW.tblcoursRepo.All
.Where(c => c.MainHeadingID == headingId)
.Where(predicate))
.ToList();
lazyberezovsky's answer fails due to an EF bug (which is not surprising given the quality of EF's LINQ support). It can be made to work with a hack:
.SelectMany(g => g.Key == 180 ? g.Take(int.MaxValue) : g.Take(1))
or
.SelectMany(g => g.Take(g.Key == 180 ? int.MaxValue : 1))
Note that performance will not be particularly good due to the way this is translated to SQL.

Finding n-Most Popular Using Linq

How should I structure a Linq query to return a List or Ienumerable of the most popular Tags in my db (I am using EF4.1 by the way).
Currently I have:
var tagsListing = db.Tags
.GroupBy(q => q.Name)
.OrderByDescending(gp => gp.Count())
.Take(5)
.Select();
I think I am part of the way there, but I am unsure of how to structure the Select statement...
Your Select call could look like this:
.Select(gp => gp.Key)
That will give you an IEnumerable<string> of your most popular tags (assuming that Name is a string).
Assuming you want the name and the count, just:
.Select(g => new { Name = g.Key, Count = g.Count() });
EDIT: If you want the complete tags as well, you could use:
.Select(g => new { Tags = g, Count = g.Count() })
which would give you a sequence of groups of tags, all with the same name within a group. Or you might only want the first tag within each group, e.g.
.Select(g => g.First())
It's not clear what a Tag consists of, or what exactly you want in the results.
You've written a perfectly workable query and do not need to call .Select
IQueryable<IGrouping<string, Tag>> tagsListing = db.Tags
.GroupBy(q => q.Name)
.OrderByDescending(gp => gp.Count())
.Take(5);
List<IGrouping<string, Tag>> results = tagListing.ToList();
You probably want to select the names like this:
.Select(gp => gp.Key);

Resources