我是LINQ的新手,我发现在理解每个LINQ语句串在一起的数据转换流程时有点困难。我有一个相当标准的类型SQL语句,我很难获得类似的LINQ语句。
加入和分组似乎相当直接,但是当我最终尝试将Select语句放入并放入两个表中的所有各个字段时,事情似乎对我来说是分崩离析的。我希望我可以发布一些SQL代码,然后我尝试将LINQ表达式拼凑在一起,这里的人们可以回答我的问题如何基本上应该可行。很确定LINQ全部被打败了。 : - /
我有以下SQL语句,它为我提供了一些我想要使用并传递给网格控件的数据。 (然而,使用LINQ to Objects)
这是我试图在LINQ中模拟的SQL语句:
SELECT s.STRUCTURE_ID, s.TITLE, s.PHOTO, s.PHOTO_LINK, COUNT(s.STRUCTURE_ID)
AS "How Many Activities", MIN(m.START_DATE) AS "START DATE", MAX(m.FINISH_DATE) AS "FINISH DATE"
FROM DB.STRUCTURES s
LEFT OUTER JOIN DB.ACTIVITIES m ON s.STRUCTURE_ID = m.STRUCTURE_ID
WHERE s.PARK = 'Elwood' AND m.CONTRACT_NO IS NOT NULL
GROUP BY s.STRUCTURE_ID, s.TITLE, m.STATUS, s.PHOTO, s.PHOTO_LINK
ORDER BY s.STRUCTURE_ID
DB.Structures是ONE文件
DB.Activities是MANY文件
选择的目标是选择所有具有活动,匹配特定公园和DO签订合同的结构。额外的小扭曲是获得最早的Start& amp;完成每个结构的相关活动的日期。
生成的数据集应该是一个扁平的集合,我可以按以下格式将其移交给我的网格控件:
Structure ID Description Photo Start Date Finish Date
HL-100 Activity Room 100 Yes 6/6/2011 8/26/2011
HS-400A Small Ones Gym No 5/2/2011 6/30/2011
所以,我把它放在一起的LINQ如下:
var query = from s in db.Structures
join a in db.Activities on s.Structure_ID equals a.Structure_ID into sa
from allStructs in sa.DefaultIfEmpty() // I believe this is how to get the outer join and flatten the selection?
where s.PARK == 'Elwood' && allStructs.CONTRACT_NO != ''
orderby s.Structure_ID
group s by s.Structure_ID into g
select new
{
myID = g.Key,
myDesc = //I don't know how to display the s.Title here ,
myPhoto = // I don't know how to display the s.Photo here ,
myStartDate = g.Min(c => c.START_DATE),
myEndDate = g.Max(c => c.FINISH_DATE)
};
所以,现在问题是:
在LINQ中我不清楚的一点是,当连接完成时,似乎没有出现一个具有ALL DECLARED列的单个集合,就像我将使用标准SQL语句获得的那样返回选择。这对我来说很困惑。可能有人告诉我这是否属实?似乎我应该能够“看到”'allStructs'对象中的所有列......但显然情况并非如此。
我正在努力解决的另一个主要问题是如何显示ONE文件中的列 - 我不能简单地找到导航到这些字段的方法。 (与上面的#1有什么联系。)
最后,是否有一些好的“技巧”或工具可以在LINQ表达式中逐步执行每一行,就像在调试器中可以直接使用C#代码一样?当LINQ表达式命中VS中的常规调试器时,它只是突出显示已经退出的表达式,并且当事情得到设置/执行时,您无法真正看到正在发生的事情。 (我意识到这可能在这里要求很多。)我目前正在使用控制台在表达式启动后查看事物,例如执行query.Count()或类似的事情。
我真的很感激有助于更好地理解数据如何通过此LINQ流程进行转换。我一直在这里阅读很多,MSDN&买了几本书,但我还没有得到每个人似乎都会说的“灯泡时刻”。
感谢所有......: - )
答案 0 :(得分:1)
在join
您有权访问s
(当前结构)和sa
之后,Structure_ID
的活动组。在DefaultIfEmpty()
之后,您可以访问相同的s
和allStructs
,这与原始SQL示例中的m
完全对应。你永远不会得到一个代表两个表中所有列的变量,但你也不会在SQL中得到它。
我相信LINQ to SQL足够聪明,可以在复合键上转换分组,在这种情况下,这就是你可能想要的:
var query = from s in db.Structures
join a in db.Activities on s.Structure_ID equals a.Structure_ID into sa
from m in sa.DefaultIfEmpty() // LEFT OUTER JOIN
where s.PARK == 'Elwood' && m.CONTRACT_NO != ''
orderby s.Structure_ID
group m by new { s.Structure_ID, s.Title, s.Photo } into g
select new
{
myID = g.Key.Structure_ID,
myDesc = g.Key.Title,
myPhoto = g.Key.Photo,
myStartDate = g.Min(c => c.START_DATE),
myEndDate = g.Max(c => c.FINISH_DATE)
};
请注意,为了与您的SQL保持一致,我将allStructs
切换为m
,并将group by
切换为使用m
而不是s
。 m
的值将包含在g
组中,Key
代表Structure_ID
,Title
和Photo
的元组。
对于调试,最好的方法是打开一些日志记录(DataContext.Log
属性)以查看正在生成的SQL。您还可以使用SQL事件探查器。它有时可以帮助逻辑上处理内存中的集合和LINQ to Objects,但需要注意的是,你可以在内存中实现根本不能转换为SQL的内容。
答案 1 :(得分:0)
要回答您的第二个问题,我认为您可以执行以下操作:
myDesc = g.First().Title
myPhoto = g.First().Photo