2011-03-24 91 views
2

我有以下LINQ查询,即返回我期望的结果,但它不“感觉”正确。这是LINQ查询“正确”吗?

基本上它是一个左连接。我需要UserProfile表中的所有记录。

然后LastWinnerDate是来自胜出者表(可能的多个记录)的单个记录,指示DateTime最后一条记录在该表中为用户输入。

WinnerCount是获胜者表中用户的记录数(可能有多个记录)。

Video1基本上是一个布尔值,表示在第三个表上匹配的胜者表中的用户存在或不是记录目标(应该是1行或0行)。

Quiz1与视频1匹配来自Objective Table的另一条记录(应该是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(), 
    }; 
+1

哪一部分不_feel right_ =) – gideon 2011-03-24 14:19:56

+4

尝试[代码审查(http://codereview.stackexchange.com/ ) – 2011-03-24 14:20:10

+0

我如何完成左连接。我仍然在学习LINQ,而在T-SQL中,我只是在查询的主要部分写入JOINS ... – Schenz 2011-03-24 14:21:40

回答

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"*/ 
+0

这将不会选择任何用户记录也不具有赢家记录。我需要执行外部联接来检索所有用户记录,而不管他们是否有赢家记录。 – Schenz 2011-03-24 14:25:36

+0

@Schenz,你仍然可以将外部联接提取到第一个语句中。这个想法依然如此。 – Snowbear 2011-03-24 14:28:29

+0

我试图看到它,但我仍然在学习LINQ,并且它对我来说并不明显... – Schenz 2011-03-24 14:30:22

1

查询本身很简单:只是一个主要外部查询等一系列子查询的检索实际列数据。虽然它不是查询数据的最有效方法(连接和使用窗口函数可能会使性能更好),但它是使用查询或表达式语法表示查询的唯一真实方法(SQL中的窗口函数在LINQ或支持LINQ的扩展方法中没有映射)。

请注意,您没有在代码中执行任何实际的外部连接(左侧或右侧)您正在创建子查询来检索列数据。可能值得看看由查询生成的实际SQL。你不指定你正在使用哪个ORM(这将决定如何检查它的客户端)或你正在使用哪个数据库(这将决定如何检查它在服务器端)。

如果您使用的是ADO.NET Entity Framework,则可以将查询转换为ObjectQuery并致电ToTraceString()

如果您正在使用SQL Server,你可以使用SQL Server Profiler(假设你可以访问它)来查看正在执行的SQL,也可以手动运行跟踪做同样的事情。

要执行一个外部联接在LINQ查询语法,这样做:

假设我们有两个来源alphabeta,每个都具有一个共同的Id属性,你可以从alpha选择并执行一个左中加入关于beta这样:

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 } 

不可否认,语法有点偏斜。尽管如此,它的工作原理,并在SQL将被翻译成这样的:

select 
    a.Id as IdA, 
    b.Id as Idb 

from alpha a 

left join beta b on a.Id = b.Id 
+0

我使用LLBL作为ORM,并不确定如何检查... – Schenz 2011-03-24 14:32:07

+1

@Schenz :它看起来像使用.NET跟踪机制生成SQL的LLBL输出。你可以实现一个简单的'TraceListener'类并从中监控SQL。 http://msdn.microsoft.com/en-us/library/system.diagnostics.tracelistener.aspx – 2011-03-24 15:02:09

0

它看起来好像没什么问题,但我能看到为什么多个子查询可以在一个编码器的眼睛触发效率低下的担心。

看看产生什么SQL,但(我猜你正在运行此对您的说法“表”上述数据库源),你开始担心之前。查询提供程序可以非常擅长生成高效的SQL,从而生成一个好的底层数据库查询,如果发生这种情况,那么快乐的日子(它也会给你另一个确定正确性的看法)。