此 LINQ 查询“正确”吗?
我有以下 LINQ 查询,它返回我期望的结果,但它“感觉”不正确。
基本上它是左连接。我需要 UserProfile 表中的所有记录。
那么 LastWinnerDate 是获胜者表中的单个记录(可能是多个记录),指示用户在该表中输入最后一条记录的日期时间。
WinnerCount 是获胜者表中用户的记录数(可能是多条记录)。
Video1 基本上是一个布尔值,指示获胜者表中是否存在与第三个表目标匹配的用户记录(应为 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(),
};
I have the following LINQ query, that is returning the results that I expect, but it does not "feel" right.
Basically it is a left join. I need ALL records from the UserProfile table.
Then the LastWinnerDate is a single record from the winner table (possible multiple records) indicating the DateTime the last record was entered in that table for the user.
WinnerCount is the number of records for the user in the winner table (possible multiple records).
Video1 is basically a bool indicating there is, or is not a record for the user in the winner table matching on a third table Objective (should be 1 or 0 rows).
Quiz1 is same as Video 1 matching another record from Objective Table (should be 1 or 0 rows).
Video and Quiz is repeated 12 times because it is for a report to be displayed to a user listing all user records and indicate if they have met the objectives.
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(),
};
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您多次重复
加入优胜者表
部分。为了避免这种情况,您可以将其分成几个后续的Select
。因此,您可以使用更少的代码进行两次选择,而不是进行一次巨大的选择。在您的示例中,我首先选择winner2
变量,然后再选择其他结果属性:You're repeating
join winners table
part several times. In order to avoid it you can break it into several consequentSelects
. So instead of having one huge select, you can make two selects with lesser code. In your example I would first of all selectwinner2
variable before selecting other result properties:查询本身非常简单:只是一个主要的外部查询和一系列用于检索实际列数据的子选择。虽然它不是查询所需数据的最有效方法(连接和使用窗口函数可能会为您带来更好的性能),但它是使用查询或表达式语法(SQL 中的窗口函数)表示查询的唯一真正方法在 LINQ 或支持 LINQ 的扩展方法中没有映射)。
请注意,您没有在代码中执行任何实际的外部联接(左或右);您正在创建子查询来检索列数据。可能值得查看查询生成的实际 SQL。您没有指定您正在使用哪个 ORM(这将决定如何在客户端检查它)或您正在使用哪个数据库(这将决定如何在服务器端检查它)。
如果您使用的是 ADO.NET 实体框架,则可以将查询转换为
ObjectQuery
并调用ToTraceString()
。如果您使用的是 SQL Server,则可以使用 SQL Server Profiler(假设您有权访问它)来查看正在执行的 SQL,或者您可以手动运行跟踪来执行相同的操作。
要在 LINQ 查询语法中执行外连接,请执行以下操作:
假设我们有两个源
alpha
和beta
,每个源都有一个公共Id
属性,您可以从alpha
中进行选择,并以这种方式对beta
执行左连接:诚然,语法有点倾斜。尽管如此,它仍然有效,并且会在 SQL 中被翻译成类似这样的内容:
The query itself is pretty simple: just a main outer query and a series of subselects to retrieve actual column data. While it's not the most efficient means of querying the data you're after (joins and using windowing functions will likely get you better performance), it's the only real way to represent that query using either the query or expression syntax (windowing functions in SQL have no mapping in LINQ or the LINQ-supporting extension methods).
Note that you aren't doing any actual outer joins (left or right) in your code; you're creating subqueries to retrieve the column data. It might be worth looking at the actual SQL being generated by your query. You don't specify which ORM you're using (which would determine how to examine it client-side) or which database you're using (which would determine how to examine it server-side).
If you're using the ADO.NET Entity Framework, you can cast your query to an
ObjectQuery
and callToTraceString()
.If you're using SQL Server, you can use SQL Server Profiler (assuming you have access to it) to view the SQL being executed, or you can run a trace manually to do the same thing.
To perform an outer join in LINQ query syntax, do this:
Assuming we have two sources
alpha
andbeta
, each having a commonId
property, you can select fromalpha
and perform a left join onbeta
in this way:Admittedly, the syntax is a little oblique. Nonetheless, it works and will be translated into something like this in SQL:
它对我来说看起来很好,尽管我可以理解为什么多个子查询可能会引发编码员眼中效率低下的担忧。
在你开始担心之前,先看看生成了什么 SQL(我猜你正在针对上面所说的“表”中的数据库源运行它)。查询提供程序可以非常擅长生成高效的 SQL,进而生成良好的底层数据库查询,如果发生这种情况,那就幸福了(它还会为您提供确保正确性的另一种观点)。
It looks fine to me, though I could see why the multiple sub-queries could trigger inefficiency worries in the eyes of a coder.
Take a look at what SQL is produced though (I'm guessing you're running this against a database source from your saying "table" above), before you start worrying about that. The query providers can be pretty good at producing nice efficient SQL that in turn produces a good underlying database query, and if that's happening, then happy days (it will also give you another view on being sure of the correctness).