LINQ query NotSupportedException OrderBy Average of TimeSpan - linq

var seasonPlayer = (from SeasonPlayer in db.SeasonPlayerSet
orderby SeasonPlayer.StatisticsPlayer.Average(x => x.STP_timeplay.Ticks) descending
select SeasonPlayer).ToList();
SeasonPlayer has an ICollection of StatisticsPlayer so i want to get a average of time spent on the court ordered descending by STP_timeplay which is a typ of TimeSpan. I can't get average by STP_timeplay because it isn't a decimal so i tried get average by Ticks. It throws an exception:
The specified type member 'Ticks' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.

The problem is that the Linq to Entities query provider isn't able to translate your LINQ into a Sql query which joins to the Statistics Player, averages the timeplay, grouped by season player.
Given that you appear to be iterating all Season Players, if the number of records isn't too large you could bring this all into memory like so:
var seasonPlayer = db.SeasonPlayerSet
.Include(sp => sp.StatisticsPlayer)
.ToList()
.Select(sp => new {SeasonPlayer = sp, Average = sp.StatisticsPlayer.Average(stp => stp.STP_timeplay.Ticks)})
.OrderByDescending(sp => sp.Average)
.Select(sp => SeasonPlayer)
.ToList();

Try this:-
var seasonPlayer = db.SeasonPlayerSet.ToList()
.OrderByDescending(x => x.StatisticsPlayer
.Average(z => z.STP_timeplay.Ticks);

Related

Query on a many to one and then returning the parents

I have entity Person which have ONE entity Car. The cars entities have multiple properties and one of this is color. I want to get all the persons that have a car with all the colors that is selected in a colorlist.
If person had many cars i should be able to write it like
PersonQuery.Include(c => c.Cars).Where(q=>q.Cars.Any(colors=>ListOfColors.Contains(colors.Color)));
and I want to replace Any with Where, but thats is not correct(!?). What do I miss?
If your expectation is to filter the Cars returned with each applicable Person to only the cars that match the filtered colours, then EF6 does not support this. Your query will return Persons and their cars where that person has a matching colour, but it will return all cars for that person.
One side note: when using Linq expressions, the choice of identifier should either just be a placeholder value (I.e. "x") or reflect the items being queried, not what you are querying for. For instance when writing PersonQuery.Where(c => ... you are querying against "Persons" not "Cars", so "p" would be a less confusing identifier than "c". Expanded out we would have .Where(person => person.Cars.Any(car => ...))
In EF Core 5 there is support for filtered includes:
var persons = context.Persons
.Include(p => p.Cars
.Where(c => ListOfColors.Contains(c.Color))
.Where(p => p.Cars.Any(c=>ListOfColors.Contains(c.Color)))
.ToList();
In EF 6, you would be better off selecting the Cars, then you can build the applicable Person list:
var cars = context.Cars
.Include(c => c.Person)
.Where(c => ListOfColors.Contains(c.Color))
.ToList();
var persons = cars.Select(c => c.Person).ToList();
However, a caveat to this approach is that it should only be done with a virgin DbContext, meaning a DbContext that has not loaded any other data. If for any reason the DbContext is already tracking another car of another colour for one of the applicable person records, that car would automatically be associated with the returned Person so you could easily find yourself with the odd car that doesn't match.
If you are running a DbContext scoped to the request and want to be 100% safe, you should consider projecting the results rather than dealing with the entities directly:
var results = context.Persons
.Where(p => p.Cars.Any(c => ListOfColors.Contains(c.Color)))
.Select(p => new PersonViewModel
{
PersonId = p.Id,
Name = p.Name,
MatchingCars = p.Cars
.Where(c => ListOfColors.Contains(c.Color))
.Select(c => new CarViewModel
{
CarId = c.Id,
Brand = c.Brand,
Model = c.Model,
// ...
}).ToList()
}.ToList();
This ensures that the data returned will always only be the matching coloured cars.

NotSupportedException for LINQ Queries

I am trying to get a list of a database table called oracleTimeCards whose employee id equals to the employeeID in employees list. Here is what I wrote:
LandornetSQLEntities db = new LandornetSQLEntities();
List<OracleEmployee> employees = db.OracleEmployees.Where(e => e.Office.Contains(officeName) && e.IsActive == true).Distinct().ToList();
var oracleTimeCards = db.OracleTimecards.Where(c => employees.Any(e => c.PersonID == e.PersonID)).ToList();
Anyone has any idea?
I'm going to assume you're using Entity Framework here. You can't embed calls to arbitrary LINQ extension methods inside your predicate, since EF might not know how to translate these to SQL.
Assuming you want to find all the timecards for the employees you found in your first query, you have two options. The simplest is to have a navigation property on your Employee class, named let's say TimeCards, that points to a collection of time card records for the given employee. Here's how that would work:
var oracleTimeCards = employees
.SelectMany(e => e.TimeCards)
.ToList();
If you don't want to do this for whatever reason, you can create an array of employee IDs by evaluating your first query, and use this to filter the second:
var empIDs = employees
.Select(e => e.PersonID)
.ToArray();
var oracleTimeCards = db.OracleTimecards
.Where(tc => empIDs.Contains(tc.PersonID))
.ToList();

Linq operate with aggregate function

I need to get a calculation on aggregation from linq which I hope someone can help
I have a list of objects that have 3 fields (date, saleprice and productcode) I need to get FOR EACH date (Group by date), the SUM of saleprice
/ COUNT of distinct product code.
I know how I can find the SUM alone but not calculation by another aggregate
It would be easier to answer your question with some sample code and objects. I'll assume, items is your list of objects:
items.GroupBy(obj => obj.Date)
.Select(g => new
{
Date = g.Key.Date,
Aggregate = g.Sum(obj => obj.SalePrice) / g.Select(obj => obj.ProductCode)
.Distinct().Count()
});

Groupby and where clause in Linq

I am a newbie to Linq. I am trying to write a linq query to get a min value from a set of records. I need to use groupby, where , select and min function in the same query but i am having issues when using group by clause. here is the query I wrote
var data =newTrips.groupby (x => x.TripPath.TripPathLink.Link.Road.Name)
.Where(x => x.TripPath.PathNumber == pathnum)
.Select(x => x.TripPath.TripPathLink.Link.Speed).Min();
I am not able to use group by and where together it keeps giving error .
My query should
Select all the values.
filter it through the where clause (pathnum).
Groupby the road Name
finally get the min value.
can some one tell me what i am doing wrong and how to achieve the desired result.
Thanks,
Pawan
It's a little tricky not knowing the relationships between the data, but I think (without trying it) that this should give you want you want -- the minimum speed per road by name. Note that it will result in a collection of anonymous objects with Name and Speed properties.
var data = newTrips.Where(x => x.TripPath.PathNumber == pathnum)
.Select(x => x.TripPath.TripPathLink.Link)
.GroupBy(x => x.Road.Name)
.Select(g => new { Name = g.Key, Speed = g.Min(l => l.Speed) } );
Since I think you want the Trip which has the minimum speed, rather than the speed, and I'm assuming a different data structure, I'll add to tvanfosson's answer:
var pathnum = 1;
var trips = from trip in newTrips
where trip.TripPath.PathNumber == pathnum
group trip by trip.TripPath.TripPathLink.Link.Road.Name into g
let minSpeed = g.Min(t => t.TripPath.TripPathLink.Link.Speed)
select new {
Name = g.Key,
Trip = g.Single(t => t.TripPath.TripPathLink.Link.Speed == minSpeed) };
foreach (var t in trips)
{
Console.WriteLine("Name = {0}, TripId = {1}", t.Name, t.Trip.TripId);
}

Differences between LINQ to Objects and LINQ to SQL queries

I have been using LINQ to query my POCO objects for some time, but I have not yet tried LINQ to SQL. I assume that LINQ to SQL queries are somehow converted to equivalent SQL queries and, given this, I am wondering if that affects the way LINQ to SQL queries are or should be written.
Are there any significant differences between LINQ to Objects and LINQ to SQL that affect how I should write a query for either?
The main difference is as you say, LINQ to SQL queries are converted into SQL. That means that there is code you can write which isn't actually convertible or has some subtly different semantics - and you only find that out at execution time.
For example:
var query = from person in people
where person.Age == person.GetHashCode()
select person;
will compile fine, but fail at execution time because LINQ to SQL doesn't know what to do with GetHashCode().
Basically I find LINQ to SQL a lot harder to predict than LINQ to Objects. That's not to say it's not useful - it's just a slightly different world. MS has done an amazing job at letting you write queries which very often just do what you expect them to, but it can't do everything.
LINQ to SQL will use the column DB server's collation for Where and OrderBy. LINQ to Objects will use string comparisons. So the former might be case-insensitive while the latter is case-sensitive. LINQ to Entities coalesces nulls. I presume L2S does the same, but I haven't tested. So in L2E you can do:
let foo = item.Property.SomeNullableType
... and foo will be null if Property is null. But in LINQ to Objects you'd have to do something like:
let foo = item.Property != null ? item.Property.SomeNullableType : null
... or you'd get a null exception.
MSDN reference here and here should help you out.
One difference that I run into is differences in grouping.
When you group in linq to objects, you get a hierarchically shaped result (keys, with child objects).
When you group in SQL, you get keys and aggregates only.
When you group in linq to sql, if you ask for the child objects (more than aggregates), linq to sql will re-query each group using the key to get those child objects. If you have thousands of groups, that can be thousands of roundtrips.
//this is ok
var results = db.Orders
.GroupBy( o => o.CustomerID )
.Select(g => new
{
CustomerId = g.Key,
OrderCount = g.Count()
});
//this could be a lot of round trips.
var results = db.Orders
.GroupBy( o => o.CustomerID )
.Select(g => new
{
CustomerId = g.Key,
OrderIds = g.Select(o => o.OrderId)
});
// this is ok
// used ToList to separate linqtosql work from linqtoObject work
var results = db.Orders
.Select(o => new {o.CustomerId, o.OrderId})
.ToList()
.GroupBy(o => o.CustomerId)
.Select(g => new
{
CustomerId = g.Key,
OrderIds = g.Select(o => o.OrderId)
});

Resources