C# 这是LINQ查询吗;“正确吗?”;?

C# 这是LINQ查询吗;“正确吗?”;?,c#,.net,linq,.net-4.0,C#,.net,Linq,.net 4.0,我有以下LINQ查询,即返回我期望的结果,但它“感觉”不对 基本上它是一个左连接。我需要UserProfile表中的所有记录 LastWinnerDate是winner表中的一条记录(可能有多条记录),指示用户在该表中输入最后一条记录的日期时间 WinnerCount是winner表中用户的记录数(可能有多条记录) Video1基本上是一个bool,表示在与第三个表目标(应该是1行或0行)匹配的winner表中有或没有用户的记录 Quiz1与视频1相同,视频1匹配目标表中的另一条记录(应为1行或

我有以下LINQ查询,即返回我期望的结果,但它“感觉”不对

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

LastWinnerDate是winner表中的一条记录(可能有多条记录),指示用户在该表中输入最后一条记录的日期时间

WinnerCount是winner表中用户的记录数(可能有多条记录)

Video1基本上是一个bool,表示在与第三个表目标(应该是1行或0行)匹配的winner表中有或没有用户的记录

Quiz1与视频1相同,视频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(),
    };
var objectiveIds=new List();
AddRange(getObjectiveId(objectiveName,false));
变量q=
在MetaData.UserProfile中从上到下
选择新的排列方式
{
UserId=up.UserId,
FirstName=up.FirstName,
LastName=up.LastName,
最后一个WinnerDate=(
来自元数据中的winner。winner
其中ObjectiveID.Contains(winner.ObjectiveID)
哪里是赢家。活动
其中winner.UserID==up.UserID
orderby winner.CreatedOn
选择winner.CreatedOn).First(),
WinnerCount=(
来自元数据中的winner。winner
其中ObjectiveID.Contains(winner.ObjectiveID)
哪里是赢家。活动
其中winner.UserID==up.UserID
orderby winner.CreatedOn
选择赢家)。计数(),
视频1=(
来自元数据中的winner。winner
在元数据中加入o。winner.ObjectiveID上的Objective等于o.ObjectiveID
其中o.ObjectiveNm==Constants.Promotions.SecVideo1
哪里是赢家。活动
其中winner.UserID==up.UserID
选择赢家)。计数(),
Quiz1=(
来自元数据中的winner2。Winner
将o2加入元数据。winner2.ObjectiveID上的目标等于o2.ObjectiveID
其中o2.ObjectiveNm==Constants.Promotions.SecQuiz1
winner2.Active在哪里
其中winner2.UserID==up.UserID
选择winner2.Count(),
};

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

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

如果使用的是ADO.NET实体框架,则可以将查询强制转换为
ObjectQuery
并调用
ToTraceString()

如果您使用的是SQL Server,则可以使用SQL Server Profiler(假设您有访问权限)查看正在执行的SQL,也可以手动运行跟踪来执行相同的操作

要在LINQ查询语法中执行外部联接,请执行以下操作:

假设我们有两个源
alpha
beta
,每个源都有一个公共的
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

在我看来,这很好,不过我可以理解为什么在编码人员眼中,多个子查询会引发效率低下的担忧


在您开始担心之前,先看看SQL是如何产生的(我猜您是针对上面所说的“表”中的数据库源运行的)。查询提供程序可以很好地生成高效的SQL,从而生成一个良好的底层数据库查询,如果发生这种情况,那么“快乐日子”(它还将为您提供另一种确保正确性的视图)。

您重复了几次
join winners table
部分。为了避免它,您可以将其分解为几个后续的
选择。因此,您可以使用较少的代码进行两次选择,而不是一次巨大的选择。在您的示例中,我首先选择
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"*/

什么部分感觉不对=)试试我是如何完成左连接的。我仍在学习LINQ,在T-SQL中,我只会在查询的主要部分编写连接……这不会选择任何没有赢家记录的用户记录。我需要执行外部联接来检索所有用户记录,无论它们是否有赢家记录。@Schenz,您仍然可以将外部联接提取到第一条语句中。这个想法仍然是一样的。我试着去了解它,但我仍然在学习LINQ,这对我来说还不明显…@Schenz,看看我最新的答案。从第一次查询开始,您将收到一对1)
up
对象本身2)左键连接的
winners
,因为这个
up
看起来更好,而且更容易阅读。谢谢大家!@Schenz:它看起来像是LLBL使用.NET跟踪机制生成的SQL。您可以实现一个简单的
TraceListener
类,并从中监视SQL。