Entity framework navigation property FirstOrDefault() - c#

I have the following line:
WorkPlaces.FirstOrDefault()
.WorkSteps.Where(x=>x.Failcodes_Id != null)
.OrderByDescending(x=>x.Timestamp)
.FirstOrDefault()
There are about 10-20 workplaces and each workplace have thousands of worksteps. I would like to get the last workstep for each of the workplaces.
The code above is an example from linqpad because I couldn't believe that the generated sql looks like this:
SELECT TOP (1)
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
[Extent1].[Description] AS [Description],
[Extent1].[Active] AS [Active],
[Extent1].[ProductionLine_Id] AS [ProductionLine_Id],
[Extent1].[DefaultTechnology_Id] AS [DefaultTechnology_Id],
[Extent1].[PrinterName] AS [PrinterName],
[Extent1].[Deleted] AS [Deleted],
[Extent2].[Id] AS [Id1],
[Extent1].[LoggedInUser_UserId] AS [LoggedInUser_UserId]
FROM [dbo].[WorkPlaces] AS [Extent1]
LEFT OUTER JOIN [dbo].[WorkplaceParameterSet] AS [Extent2] ON [Extent1].[Id] = [Extent2].[WorkPlace_Id]
GO
-- Region Parameters
DECLARE #EntityKeyValue1 Int = 1
-- EndRegion
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Timestamp] AS [Timestamp],
[Extent1].[Description] AS [Description],
[Extent1].[WorkPlace_Id] AS [WorkPlace_Id],
[Extent1].[WorkItemState_Id] AS [WorkItemState_Id],
[Extent1].[UserId] AS [UserId],
[Extent1].[WorkItem_Id] AS [WorkItem_Id],
[Extent1].[Technology_Id] AS [Technology_Id],
[Extent1].[Failcodes_Id] AS [Failcodes_Id],
[Extent1].[DrawingNo] AS [DrawingNo],
[Extent1].[ManualData] AS [ManualData],
[Extent1].[Deleted] AS [Deleted],
[Extent1].[WorkItemState_Arrival_Id] AS [WorkItemState_Arrival_Id]
FROM [dbo].[WorkSteps] AS [Extent1]
WHERE [Extent1].[WorkPlace_Id] = #EntityKeyValue1
Is there a way to get one line from worksteps without downloading 9000 records to pick one from the top of the list?

Rather than getting each workplace individually and then getting the workstep for that work place in a query you can use Select to project each workplace into the workstep that you want in one query:
var query = WorkPlaces.Select(workplace => workplace.WorkSteps
.Where(x => x.Failcodes_Id != null)
.OrderByDescending(x => x.Timestamp)
.FirstOrDefault());

You should use IQueryable interface instead of IEnumerable. Also check this.

Related

Linq to SQL - Order By related Table using a Where Clause

I have two related tables lets say:
Table Products (Main Table)
ID
Name
Type
Table Parts (Child of Products, contains detailled Information)
ID
ProductID
PartName
PartValue
I would like to get Products ordered by the value of a specific part (e.G. Engine)
I came up with the following:
// Code to construct a query to get all desired products
products = products.OrderBy(c => c.Parts.Where(d => d.PartName == "Engine").Select(d => d.Value).FirstOrDefault());
This works but is too slow. Can I improve the query or will I have to redsign my database so I won't be sorting like this in the first place?
Generated SQL-Query:
SELECT
[Project3].[ID] AS [ID],
[Project3].[Name] AS [Name]
FROM ( SELECT
[Project2].[ID] AS [ID],
[Project2].[Name] AS [Name],
[Project2].[C1] AS [C1]
FROM ( SELECT
[Extent1].[ID] AS [ID],
[Extent1].[Name] AS [Name],
(SELECT TOP (1)
[Extent2].[PartValue] AS [PartValue]
FROM [dbo].[Parts] AS [Extent2]
WHERE ([Extent1].[ID] = [Extent2].[ProductID]) AND (N'Engine' = [Extent2].[PartName])) AS [C1]
FROM [dbo].[Products] AS [Extent1]
WHERE (1 = [Extent1].[Type])
) AS [Project2]
) AS [Project3]
ORDER BY [Project3].[C1] ASC
If you want to try a join, it would be a bit like this:
Products
.Join(Parts, pd => pd.ID, pt => pt.ProductID, (pd, pt) => new { pd.Name, pt.PartName, pt.PartValue })
.Where(x => x.PartName == "Engine")
.OrderBy(x => x.PartValue);
This would result in a single select statement without the inner selects from before

c# Different Result between Linq and SQL

I try to fetch some data with EF6 from a MSSQL-Database:
IQueryable<Kundentree1> tmp = from f in db.Kundentree1 select f ;
Kundentree1 is a SQL-View on Database.
Because I don't all my result I'm filtering the result:
tmp = tmp.Where(k => k.Strasse
.ToLower()
.Trim().Contains(search.Strasse
.ToLower()
.Trim()))
.Distinct();
(this is not the only one, there are some more.. )
And at the end of my Procedure:
var sql = tmp.ToString();
return View(tmp);
In my testing routine tmp gives back 7 Items as result, but item 0 - 6 are the same.
If I use the SqlStatement (SQL) I also get 7 Items, but in this case, the right result, 7 different items.
Any hint where the Problem could be?
Update:
The Full-Generated SQL-CODE (and correct working)
SELECT
[Extent1].[Firmenname] AS [Firmenname],
[Extent1].[rechtsform] AS [rechtsform],
[Extent1].[Strasse] AS [Strasse],
[Extent1].[Land] AS [Land],
[Extent1].[Postleitzahl] AS [Postleitzahl],
[Extent1].[Ort] AS [Ort],
[Extent1].[Name] AS [Name],
[Extent1].[Personen_ID] AS [Personen_ID],
[Extent1].[Firmen_ID] AS [Firmen_ID],
[Extent1].[Adressen_ID] AS [Adressen_ID],
[Extent1].[sex] AS [sex],
[Extent1].[Vorwahl] AS [Vorwahl],
[Extent1].[Tel1] AS [Tel1],
[Extent1].[zahlungskondition] AS [zahlungskondition],
[Extent1].[sperrkennzeichen] AS [sperrkennzeichen],
[Extent1].[sendkatalag] AS [sendkatalag],
[Extent1].[lastkatalog] AS [lastkatalog],
[Extent1].[ID] AS [ID],
[Extent1].[NACHNAME] AS [NACHNAME],
[Extent1].[VORNAME] AS [VORNAME],
[Extent1].[ZKTEXT] AS [ZKTEXT],
[Extent1].[FAX] AS [FAX],
[Extent1].[KNR] AS [KNR],
[Extent1].[UID] AS [UID],
[Extent1].[firmenbuch] AS [firmenbuch],
[Extent1].[email] AS [email],
[Extent1].[Lieferant] AS [Lieferant],
[Extent1].[PERS_VORNAME] AS [PERS_VORNAME],
[Extent1].[PERS_NACHNAME] AS [PERS_NACHNAME],
[Extent1].[PERS_sex] AS [PERS_sex],
[Extent1].[Titel] AS [Titel],
[Extent1].[Zusatz] AS [Zusatz],
[Extent1].[Position] AS [Position],
[Extent1].[PERS_EMAIL] AS [PERS_EMAIL],
[Extent1].[PERSONEN_GRUPPE_ID] AS [PERSONEN_GRUPPE_ID],
[Extent1].[NEWSLETTER] AS [NEWSLETTER],
[Extent1].[HEROLD_ID] AS [HEROLD_ID],
[Extent1].[INFOTEXT] AS [INFOTEXT],
[Extent1].[DISG] AS [DISG],
[Extent1].[HANDEL] AS [HANDEL],
[Extent1].[AdressenTYP] AS [AdressenTYP],
[Extent1].[BUNDESLAND] AS [BUNDESLAND],
[Extent1].[CANBOX] AS [CANBOX],
[Extent1].[KatalogTyp] AS [KatalogTyp],
[Extent1].[KatalogBezeichnung] AS [KatalogBezeichnung]
FROM (SELECT
[Kundentree1].[Firmenname] AS [Firmenname],
[Kundentree1].[rechtsform] AS [rechtsform],
[Kundentree1].[Strasse] AS [Strasse],
[Kundentree1].[Land] AS [Land],
[Kundentree1].[Postleitzahl] AS [Postleitzahl],
[Kundentree1].[Ort] AS [Ort],
[Kundentree1].[Name] AS [Name],
[Kundentree1].[Personen_ID] AS [Personen_ID],
[Kundentree1].[Firmen_ID] AS [Firmen_ID],
[Kundentree1].[Adressen_ID] AS [Adressen_ID],
[Kundentree1].[sex] AS [sex],
[Kundentree1].[Vorwahl] AS [Vorwahl],
[Kundentree1].[Tel1] AS [Tel1],
[Kundentree1].[zahlungskondition] AS [zahlungskondition],
[Kundentree1].[sperrkennzeichen] AS [sperrkennzeichen],
[Kundentree1].[sendkatalag] AS [sendkatalag],
[Kundentree1].[lastkatalog] AS [lastkatalog],
[Kundentree1].[ID] AS [ID],
[Kundentree1].[NACHNAME] AS [NACHNAME],
[Kundentree1].[VORNAME] AS [VORNAME],
[Kundentree1].[ZKTEXT] AS [ZKTEXT],
[Kundentree1].[FAX] AS [FAX],
[Kundentree1].[KNR] AS [KNR],
[Kundentree1].[UID] AS [UID],
[Kundentree1].[firmenbuch] AS [firmenbuch],
[Kundentree1].[email] AS [email],
[Kundentree1].[Lieferant] AS [Lieferant],
[Kundentree1].[PERS_VORNAME] AS [PERS_VORNAME],
[Kundentree1].[PERS_NACHNAME] AS [PERS_NACHNAME],
[Kundentree1].[PERS_sex] AS [PERS_sex],
[Kundentree1].[Titel] AS [Titel],
[Kundentree1].[Zusatz] AS [Zusatz],
[Kundentree1].[Position] AS [Position],
[Kundentree1].[PERS_EMAIL] AS [PERS_EMAIL],
[Kundentree1].[PERSONEN_GRUPPE_ID] AS [PERSONEN_GRUPPE_ID],
[Kundentree1].[NEWSLETTER] AS [NEWSLETTER],
[Kundentree1].[HEROLD_ID] AS [HEROLD_ID],
[Kundentree1].[INFOTEXT] AS [INFOTEXT],
[Kundentree1].[DISG] AS [DISG],
[Kundentree1].[HANDEL] AS [HANDEL],
[Kundentree1].[AdressenTYP] AS [AdressenTYP],
[Kundentree1].[BUNDESLAND] AS [BUNDESLAND],
[Kundentree1].[CANBOX] AS [CANBOX],
[Kundentree1].[KatalogTyp] AS [KatalogTyp],
[Kundentree1].[KatalogBezeichnung] AS [KatalogBezeichnung]
FROM [dbo].[Kundentree1] AS [Kundentree1]) AS [Extent1]
WHERE (( CAST(CHARINDEX(LTRIM(RTRIM(LOWER('Salv'))), LTRIM(RTRIM(LOWER([Extent1].[Firmenname])))) AS int)) > 0) AND ( NOT (([Extent1].[Postleitzahl] IS NULL) OR ((LEN([Extent1].[Postleitzahl])) = 0))) AND (( CAST(CHARINDEX(LTRIM(RTRIM('4482')), LTRIM(RTRIM([Extent1].[Postleitzahl]))) AS int)) > 0)
thanks to Ivan Stoev:
Creating a key on the view on database works
in my case it is a fake key (uniqueidentifier newID()) which i need to work

What is the difference between these LINQ queries

I've been fooling around with some LINQ over Entities and I'm getting strange results and I would like to get an explanation...
Given the following LINQ query,
// Sample # 1
IEnumerable<GroupInformation> groupingInfo;
groupingInfo = from a in context.AccountingTransaction
group a by a.Type into grp
select new GroupInformation()
{
GroupName = grp.Key,
GroupCount = grp.Count()
};
I get the following SQL query (taken from SQL Profiler):
SELECT
1 AS [C1],
[GroupBy1].[K1] AS [Type],
[GroupBy1].[A1] AS [C2]
FROM ( SELECT
[Extent1].[Type] AS [K1],
COUNT(1) AS [A1]
FROM [dbo].[AccountingTransaction] AS [Extent1]
GROUP BY [Extent1].[Type]
) AS [GroupBy1]
So far so good.
If I change my LINQ query to:
// Sample # 2
groupingInfo = context.AccountingTransaction.
GroupBy(a => a.Type).
Select(grp => new GroupInformation()
{
GroupName = grp.Key,
GroupCount = grp.Count()
});
it yields to the exact same SQL query. Makes sense to me.
Here comes the interesting part... If I change my LINQ query to:
// Sample # 3
IEnumerable<AccountingTransaction> accounts;
IEnumerable<IGrouping<object, AccountingTransaction>> groups;
IEnumerable<GroupInformation> groupingInfo;
accounts = context.AccountingTransaction;
groups = accounts.GroupBy(a => a.Type);
groupingInfo = groups.Select(grp => new GroupInformation()
{
GroupName = grp.Key,
GroupCount = grp.Count()
});
the following SQL is executed (I stripped a few of the fields from the actual query, but all the fields from the table (~ 15 fields) were included in the query, twice):
SELECT
[Project2].[C1] AS [C1],
[Project2].[Type] AS [Type],
[Project2].[C2] AS [C2],
[Project2].[Id] AS [Id],
[Project2].[TimeStamp] AS [TimeStamp],
-- <snip>
FROM ( SELECT
[Distinct1].[Type] AS [Type],
1 AS [C1],
[Extent2].[Id] AS [Id],
[Extent2].[TimeStamp] AS [TimeStamp],
-- <snip>
CASE WHEN ([Extent2].[Id] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C2]
FROM (SELECT DISTINCT
[Extent1].[Type] AS [Type]
FROM [dbo].[AccountingTransaction] AS [Extent1] ) AS [Distinct1]
LEFT OUTER JOIN [dbo].[AccountingTransaction] AS [Extent2] ON [Distinct1].[Type] = [Extent2].[Type]
) AS [Project2]
ORDER BY [Project2].[Type] ASC, [Project2].[C2] ASC
Why are the SQLs generated are so different? After all, the exact same code is executed, it's just that sample # 3 is using intermediate variables to get the same job done!
Also, if I do:
Console.WriteLine(groupingInfo.ToString());
for sample # 1 and sample # 2, I get the exact same query that was captured by SQL Profiler, but for sample # 3, I get:
System.Linq.Enumerable+WhereSelectEnumerableIterator`2[System.Linq.IGrouping`2[System.Object,TestLinq.AccountingTransaction],TestLinq.GroupInformation]
What is the difference? Why can't I get the SQL Query generated by LINQ if I split the LINQ query in multiple instructions?
The ulitmate goal is to be able to add operators to the query (Where, OrderBy, etc.) at run-time.
BTW, I've seen this behavior in EF 4.0 and EF 6.0.
Thank you for your help.
The reason is because in your third attempt you're referring to accounts as IEnumerable<AccountingTransaction> which will cause the query to be invoked using Linq-To-Objects (Enumerable.GroupBy and Enumerable.Select)
On the other hand, in your first and second attempts the reference to AccountingTransaction is preserved as IQueryable<AccountingTransaction> and the query will be executed using Linq-To-Entities which will then transform it to the appropriate SQL statement.

Is Linq Include broken when used with joins and where clauses?

I have been experimenting trying to get the following Linq working without joy. I'm convinced that it's right, but that might just be my bad Linq. I originally added this as a answer to a similar question here:
Linq-to-entities - Include() method not loading
But as it's a very old question, and mine is more specific, I figured it would do better as an explicit question.
In the linked question, Alex James gives two interesting solutions, however if you try them and check the SQL, it's horrible.
The example I was working on is:
var theRelease = from release in context.Releases
where release.Name == "Hello World"
select release;
var allProductionVersions = from prodVer in context.ProductionVersions
where prodVer.Status == 1
select prodVer;
var combined = (from release in theRelease
join p in allProductionVersions on release.Id equals p.ReleaseID
select release).Include(release => release.ProductionVersions);
var allProductionsForChosenRelease = combined.ToList();
This follows the simpler of the two examples. Without the include it produces the perfectly respectable sql:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name]
FROM [dbo].[Releases] AS [Extent1]
INNER JOIN [dbo].[ProductionVersions] AS [Extent2] ON [Extent1].[Id] = [Extent2].[ReleaseID]
WHERE ('Hello World' = [Extent1].[Name]) AND (1 = [Extent2].[Status])
But with, OMG:
SELECT
[Project1].[Id1] AS [Id],
[Project1].[Id] AS [Id1],
[Project1].[Name] AS [Name],
[Project1].[C1] AS [C1],
[Project1].[Id2] AS [Id2],
[Project1].[Status] AS [Status],
[Project1].[ReleaseID] AS [ReleaseID]
FROM ( SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
[Extent2].[Id] AS [Id1],
[Extent3].[Id] AS [Id2],
[Extent3].[Status] AS [Status],
[Extent3].[ReleaseID] AS [ReleaseID],
CASE WHEN ([Extent3].[Id] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1]
FROM [dbo].[Releases] AS [Extent1]
INNER JOIN [dbo].[ProductionVersions] AS [Extent2] ON [Extent1].[Id] = [Extent2].[ReleaseID]
LEFT OUTER JOIN [dbo].[ProductionVersions] AS [Extent3] ON [Extent1].[Id] = [Extent3].[ReleaseID]
WHERE ('Hello World' = [Extent1].[Name]) AND (1 = [Extent2].[Status])
) AS [Project1]
ORDER BY [Project1].[Id1] ASC, [Project1].[Id] ASC, [Project1].[C1] ASC
Total garbage. The key point to note here is the fact that it returns the outer joined version of the table which has not been limited by status=1.
This results in the WRONG data being returned:
Id Id1 Name C1 Id2 Status ReleaseID
2 1 Hello World 1 1 2 1
2 1 Hello World 1 2 1 1
Note that the status of 2 is being returned there, despite our restriction. It simply does not work.
If I have gone wrong somewhere, I would be delighted to find out, as this is making a mockery of Linq. I love the idea, but the execution doesn't seem to be usable at the moment.
Out of curiosity, I tried the LinqToSQL dbml rather than the LinqToEntities edmx that produced the mess above:
SELECT [t0].[Id], [t0].[Name], [t2].[Id] AS [Id2], [t2].[Status], [t2].[ReleaseID], (
SELECT COUNT(*)
FROM [dbo].[ProductionVersions] AS [t3]
WHERE [t3].[ReleaseID] = [t0].[Id]
) AS [value]
FROM [dbo].[Releases] AS [t0]
INNER JOIN [dbo].[ProductionVersions] AS [t1] ON [t0].[Id] = [t1].[ReleaseID]
LEFT OUTER JOIN [dbo].[ProductionVersions] AS [t2] ON [t2].[ReleaseID] = [t0].[Id]
WHERE ([t0].[Name] = #p0) AND ([t1].[Status] = #p1)
ORDER BY [t0].[Id], [t1].[Id], [t2].[Id]
Slightly more compact - weird count clause, but overall same total FAIL.
Please tell me I've missed something obvious, as I really want to like Linq!
Okay, after another evening of head scratching I cracked it.
In LinqToSQL:
using (var context = new TestSQLModelDataContext())
{
context.DeferredLoadingEnabled = false;
DataLoadOptions ds = new DataLoadOptions();
ds.LoadWith<ProductionVersion>(prod => prod.Release);
context.LoadOptions = ds;
var combined = from release in context.Releases
where release.Name == "Hello World"
select from prodVer in release.ProductionVersions
where prodVer.Status == 1
select prodVer;
var allProductionsForChosenRelease = combined.ToList();
}
This produces the much more reasonable SQL:
SELECT [t2].[Id], [t2].[Status], [t2].[ReleaseID], [t0].[Id] AS [Id2], [t0].[Name], (
SELECT COUNT(*)
FROM [dbo].[ProductionVersions] AS [t3]
WHERE ([t3].[Status] = 1) AND ([t3].[ReleaseID] = [t0].[Id])
) AS [value]
FROM [dbo].[Releases] AS [t0]
OUTER APPLY (
SELECT [t1].[Id], [t1].[Status], [t1].[ReleaseID]
FROM [dbo].[ProductionVersions] AS [t1]
WHERE ([t1].[Status] =1) AND ([t1].[ReleaseID] = [t0].[Id])
) AS [t2]
WHERE [t0].[Name] = 'Hello World'
ORDER BY [t0].[Id], [t2].[Id]
Which produces the correct results:
Id Status ReleaseID Id2 Name value
2 1 1 1 Hello World 1
And in LinqToEntities (I couldn't get the Include syntax to work, so I use the quirk where including the desired table in the results links it up correctly):
using (var context = new TestEntities1())
{
var combined = (from release in context.Releases
where release.Name == "Hello World"
select from prodVer in release.ProductionVersions
where prodVer.Status == 1
select new { prodVer, Release =prodVer.Release });
var allProductionsForChosenRelease = combined.ToList();
}
And this produces the SQL:
SELECT
[Project1].[Id] AS [Id],
[Project1].[C1] AS [C1],
[Project1].[Id1] AS [Id1],
[Project1].[Status] AS [Status],
[Project1].[ReleaseID] AS [ReleaseID],
[Project1].[Id2] AS [Id2],
[Project1].[Name] AS [Name]
FROM ( SELECT
[Extent1].[Id] AS [Id],
[Join1].[Id1] AS [Id1],
[Join1].[Status] AS [Status],
[Join1].[ReleaseID] AS [ReleaseID],
[Join1].[Id2] AS [Id2],
[Join1].[Name] AS [Name],
CASE WHEN ([Join1].[Id1] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1]
FROM [dbo].[Releases] AS [Extent1]
LEFT OUTER JOIN (SELECT [Extent2].[Id] AS [Id1], [Extent2].[Status] AS [Status], [Extent2].[ReleaseID] AS [ReleaseID], [Extent3].[Id] AS [Id2], [Extent3].[Name] AS [Name]
FROM [dbo].[ProductionVersions] AS [Extent2]
INNER JOIN [dbo].[Releases] AS [Extent3] ON [Extent2].[ReleaseID] = [Extent3].[Id] ) AS [Join1] ON ([Extent1].[Id] = [Join1].[ReleaseID]) AND (1 = [Join1].[Status])
WHERE 'Hello World' = [Extent1].[Name]
) AS [Project1]
ORDER BY [Project1].[Id] ASC, [Project1].[C1] ASC
Which is fairly mental, but it does work.
Id C1 Id1 Status ReleaseID Id2 Name
1 1 2 1 1 1 Hello World
All of which leads me to the conclusion that Linq is far from finished. It can be used, but with extreme caution. Use it as a strongly typed and compile time checked, but laborious/error prone, way of writing bad SQL. It's a trade-off. You get more security at the C# end, but man it's a lot harder than writing SQL!
Taking a second look, I now understand the elusive effect of the Include.
Just as in plain SQL, a join in LINQ will repeat results when the right side of the join is the "n" end of a 1-n association.
Let's assume you have one Release with two ProductionVersions. Without the Include, the join will give you two identical Releases, because after all the statement selects releases. Now when you add the Include, EF will not only return two releases, but will also fully populate their ProductionVersions collections.
Looking a bit deeper, in the context's cache, it appears that EF really only materialized just 1 Release and 2ProductionVersions. It's just that the releases are returned twice in the final result set.
In a way, you got what you asked for: give me releases, multiplied by their number of versions. But that's not what you intended to ask.
What you (probably) intended reveals a weak spot in EF's toolbox: we can't Include partial collections. I think you tried to get releases populated with ProductionVersions of Status = 1 only. If possible, you'd rather have done this:
context.Releases.Include(r => r.ProductionVersions.Where(v => v.Status == 1))
.Where(r => r.Name == "Hello World")
But that throws an exception:
The Include path expression must refer to a navigation property defined on the type. Use dotted paths for reference navigation properties and the Select operator for collection navigation properties.
Parameter name: path
This "filtered include" problem has been noted before and until the EF team (or a contributor) decides to grab this issue we have to do with elaborate work-arounds. I described a common one here.

Linq to SQL sort by fields in 2 entities (parent-child)

I have 2 entities called Request and Days. Request has many days and what I am having problems with is properly sorting my entities the way I want to.
Days has a certain field called Hours and I need to sort it first by the Hours field in days (however, first are ALL of the fields that have only one day) and then, by then number of Days in a Request.
I've tried many orderby/thenby combinations and can't get this quite right.
Here is a recent one I've tried:
sortingFunction = x => x.Days.OrderBy(h => h.Hours).Count();
Any help with this?
from r in db.Requests
let daysCount = r.Days.Count()
orderby daysCount == 1 ? r.Days.FirstOrDefault().Hours : Int32.MaxValue,
daysCount
select r
Generated SQL query will look like:
SELECT
[Project4].[Id] AS [Id],
[Project4].[Foo] AS [Foo]
FROM ( SELECT
CASE WHEN ((1 = [Project3].[C1]) AND ([Project3].[C1] IS NOT NULL))
THEN [Project3].[C2] ELSE 2147483647 END AS [C1],
[Project3].[Id] AS [Id],
[Project3].[Foo] AS [Foo]
[Project3].[C1] AS [C2]
FROM ( SELECT
[Project1].[Id] AS [Id],
[Project1].[Foo] AS [Foo]
[Project1].[C1] AS [C1], // count of days
(SELECT TOP (1) // C2 is hours of first day
[Extent3].[Hours] AS [Hours]
FROM [dbo].[Days] AS [Extent3]
WHERE [Project1].[Id] = [Extent3].[RequestId]) AS [C2]
FROM (SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Foo] AS [Foo]
(SELECT
COUNT(1) AS [A1]
FROM [dbo].[Days] AS [Extent2]
WHERE [Extent1].[Id] = [Extent2].[RequestId]) AS [C1]
FROM [dbo].[Requests] AS [Extent1]
) AS [Project1]
) AS [Project3]
) AS [Project4]
ORDER BY [Project4].[C1] ASC, [Project4].[C2] ASC

Categories