我有以下LINQ查询,即返回我期望的结果,但它没有“感觉”正确。
基本上它是左连接。我需要UserProfile表中的所有记录。
然后,LastWinnerDate是来自获胜者表的一条记录(可能是多条记录),表示在该表中为该用户输入的最后一条记录的日期时间。
WinnerCount是获胜者表中用户的记录数(可能是多个记录)。
Video1基本上是一个bool,表示在第三个表Objective上匹配的wins table表中存在或者不是用户的记录(应该是1或0行)。
Quiz1与视频1相同,与目标表中的另一条记录相匹配(应为1或0行)。
视频和测验重复12次,因为报告会显示给列出所有用户记录的用户,并指出他们是否达到了目标。
var objectiveIds = new List<int>();
objectiveIds.AddRange(GetObjectiveIds(objectiveName, false));
var q =
from up in MetaData.UserProfile
select new RankingDTO
{
UserId = up.UserID,
FirstName = up.FirstName,
LastName = up.LastName,
LastWinnerDate = (
from winner in MetaData.Winner
where objectiveIds.Contains(winner.ObjectiveID)
where winner.Active
where winner.UserID == up.UserID
orderby winner.CreatedOn descending
select winner.CreatedOn).First(),
WinnerCount = (
from winner in MetaData.Winner
where objectiveIds.Contains(winner.ObjectiveID)
where winner.Active
where winner.UserID == up.UserID
orderby winner.CreatedOn descending
select winner).Count(),
Video1 = (
from winner in MetaData.Winner
join o in MetaData.Objective on winner.ObjectiveID equals o.ObjectiveID
where o.ObjectiveNm == Constants.Promotions.SecVideo1
where winner.Active
where winner.UserID == up.UserID
select winner).Count(),
Quiz1 = (
from winner2 in MetaData.Winner
join o2 in MetaData.Objective on winner2.ObjectiveID equals o2.ObjectiveID
where o2.ObjectiveNm == Constants.Promotions.SecQuiz1
where winner2.Active
where winner2.UserID == up.UserID
select winner2).Count(),
};
答案 0 :(得分:1)
查询本身非常简单:只需要一个主外部查询和一系列子选择来检索实际的列数据。虽然它不是查询您所追求的数据的最有效方法(连接和使用窗口函数可能会让您获得更好的性能),但它是使用查询或表达式语法(SQL中的窗口函数)表示该查询的唯一真实方式。在LINQ或支持LINQ的扩展方法中没有映射。)
请注意,您的代码中没有进行任何实际的外部连接(左侧或右侧);您正在创建子查询以检索列数据。可能值得查看查询生成的实际SQL。您没有指定您正在使用哪个ORM(这将决定如何在客户端检查它)或您正在使用哪个数据库(这将决定如何在服务器端检查它)。
如果您使用的是ADO.NET实体框架,则可以将查询转换为ObjectQuery
并致电ToTraceString()
。
如果您正在使用SQL Server,则可以使用SQL Server Profiler(假设您有权访问它)来查看正在执行的SQL,或者您可以手动运行跟踪来执行相同的操作。
要在LINQ查询语法中执行外部联接,请执行以下操作:
假设我们有两个来源alpha
和beta
,每个来源都有一个共同的Id
属性,您可以从alpha
中选择并在{{1}上执行左连接以这种方式:
beta
不可否认,语法有点倾斜。尽管如此,它仍然有效,并将在SQL中翻译成这样的东西:
from a in alpha
join btemp in beta on a.Id equals btemp.Id into bleft
from b in bleft.DefaultIfEmpty()
select new { IdA = a.Id, IdB = b.Id }
答案 1 :(得分:1)
您多次重复join winners table
部分。为了避免它,你可以把它分成几个结果Selects
。因此,您可以使用较少的代码进行两次选择,而不是使用一个巨大的选择。在您的示例中,我首先选择winner2
变量,然后选择其他结果属性:
var q1 =
from up in MetaData.UserProfile
select new {up,
winners = from winner in MetaData.Winner
where winner.Active
where winner.UserID == up.UserID
select winner};
var q = from upWinnerPair in q1
select new RankingDTO
{
UserId = upWinnerPair.up.UserID,
FirstName = upWinnerPair.up.FirstName,
LastName = upWinnerPair.up.LastName,
LastWinnerDate = /* Here you will have more simple and less repeatable code
using winners collection from "upWinnerPair.winners"*/
答案 2 :(得分:0)
对我而言看起来很好,但我可以理解为什么多个子查询会在编码器眼中引发效率低下的问题。
看一下虽然生成了什么SQL(我猜你是从上面的“表”中对数据库源运行的),然后才开始担心这个问题。查询提供程序可以很好地生成优质高效的SQL,从而产生良好的底层数据库查询,如果发生这种情况,那么快乐的日子(它还会为您提供另一种确定正确性的视图)。