Convert an SQL statement into LINQ-To-SQL

匿名 (未验证) 提交于 2019-12-03 00:48:01

问题:

can I get a hand converting the following into a LINQ statement.

SELECT reports.* FROM [dbo].[ReportLists] rl INNER JOIN [dbo].[ReportItems] ri ON rl.Id = ri.ReportListId INNER JOIN [dbo].[Reports] reports ON ri.Id = reports.ReportItemId WHERE     reports.createdDate IN (     SELECT          MAX(report_max_dates.createdDate)      FROM          [dbo].[Reports] report_max_dates     GROUP BY          report_max_dates.seedLot     ) 

Currently I have it down to this:

db.ReportLists.Select(rl => db.ReportItems                             .Where(ri => ri.ReportListId == rl.Id)                             .Select(ri => db.Reports                                           .Where(r => r.ReportItemId == ri.Id)                                           .GroupBy(r => new { r.seedLot })                                           .Select(g => g.OrderByDescending(x => x.createdDate).FirstOrDefault()))); 

The problem with the LINQ above is that it returns entries that have titles changed. Within the database I keep history of all records (hence the need for the first on the createdDate order descending. When I change a report from title x to title y, it shows up under both titles when I only want the most recent record which would hence be the one under title y.

EDIT Sorry for the lack of detail. I have a reports table which holds info about the report (seedlot being an identifier). Whenever a report is edited, a new record is inserted (vs updating the old one) such that history is kept. In this case then the max entry for the createdDate indicates that the report is the most recent record to be displayed. Reports are then grouped into titles or ReportItems. These report items hold the title and associated reports. These reportItems are held in a ReportList such that I can print out the JSON in a desired format and just contains a status column and id linked to by the ReportItems.

In the event that a report is moved from title a to title b, a new record is entered with the title foreign key linking up to the title it was changed to. When this happens the above given LINQ returns the record under each individual ReportItem when it should only return the newest entry for title b (from the example above). Other than this the LINQ statement only returns the most recent record for the createdDate.

Here are my class structures (which mimic the DB structure as well)

public class ReportList {     public int Id {get;set;}     public string status {get;set;}     public List<ReportItem> {get;set;} }  public class ReportItem {     public int Id {get;set}     public string title {get;set;}     public List<Report> {get;set;} }  public class Report {     public int Id {get;set;}     public string Lot {get;set;}     ... Other data ...     public DateTime createdDate {get;set;} } 

Thanks, Dman

回答1:

If I understood it right, then you want latest report by seedLot, then I'd use next:

from r in Reports group r by r.CreateDate into g select g.OrderByDescending(r1=>r1.CreateDate).FirstOrDefault() 

Not quite sure why do you need ReportItem and ReportList if you do not include them into result, by you can traverse up to them with Report's navigational properties.



回答2:

The details you provide make it much clearer, although not entirely, so I'll give two alternatives. The navigation properties come in handy, as now very concise comprehensive syntax is possible:

from rl in context.ReportLists from ri in rl.ReportItems from r in ri.Reports group r by r.Lot into g select g.OrderByDescending(x => x.createdDate).FirstOrDefault() 

or (since you seem to group by Title in ReportItems):

from rl in context.ReportLists from ri in rl.ReportItems group ri by ri.Title into g select g.Select(x => x.Reports                       .OrderByDescending(x => x.createdDate).FirstOrDefault()) 

under the hood this also produces SQL joins, but you don't need the awkward syntax. In linq fluent syntax it boils down to SelectMany()s.

As you see, I still can't figure out the role of Lot and Title but I hope the alternatives will give some substance to mould to your own specifications.



回答3:

Ah. I see. Your Inner Join is culling out those records that have no Id in the ReportItems table and ReportItems that have no Id in the ReportLists table. Since you're not using inner join syntax in Linq, they aren't equivalent. Have you tried this:

var reports = from rl in db.ReportLists               from ri in rl.ReportItems                from r in ri.Reports               where (                   from report in db.Reports                   group report by report.seedLot into g                   select g.Max(rep => rep.createdDate)).Contains(r.CreatedDate)               select rl; 

I'm not 100% that I've got the syntax right on that group with Contains (I don't do a lot of grouping day-to-day). And if the LINQ provider doesn't support the Max (or Contains, though it should) then it'll pull eveything client-side and that's a lot of data to push over the wire.



回答4:

Changed the database schema to sorta flatten it out a bit a take out a lot of the branching.

Report is now the root and I just have a table of titles that get attached to the reports.

Thanks to all for the suggestions tho!



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!