我正在尝试将这个非常简单的SQL转换为LINQ:
select * from Projects p
inner join Documents d
on p.ProjectID = d.ProjectID
left join Revisions r
on r.DocumentID = d.DocumentID
and r.RevisionID IN (SELECT max(r2.RevisionID) FROM Revisions r2 GROUP BY r2.DocumentID)
WHERE p.ProjectID = 21 -- Query string in code
这就是说,如果文档存在任何修订,请返回最高版本ID。由于它是左连接,如果不存在修订,我仍然希望返回结果。
这可以正常工作,显示存在的任何修订(并返回最高版本ID),所有文档都没有任何修订。
当尝试使用LINQ编写它时,我只得到文档存在修订的结果。
到目前为止,这是我的尝试:
var query = from p in db.Projects
join d in db.Documents on new { ProjectID = p.ProjectID } equals new { ProjectID = Convert.ToInt32(d.ProjectID) }
join r in db.Revisions on new { DocumentID = d.DocumentID } equals new { DocumentID = Convert.ToInt32(r.DocumentID) } into r_join
from r in r_join.DefaultIfEmpty()
where
(from r2 in db.Revisions
group r2 by new { r2.DocumentID }
into g
select new { MaxRevisionID = g.Max(x => x.RevisionID) }).Contains(
new { MaxRevisionID = r.RevisionID }) &&
p.ProjectID == Convert.ToInt32(Request.QueryString["projectId"])
select new { d.DocumentID, d.DocumentNumber, d.DocumentTitle, RevisionNumber = r.RevisionNumber ?? "<No rev>", Status = r.DocumentStatuse == null ? "<Not set>" : r.DocumentStatuse.Status };
我不是很擅长LINQ并且一直使用转换器“Linqer”来帮助我,但在尝试时我得到以下信息:
“SQL无法在JOIN表达式中转换为LINQ:Only”=“运算符 可以使用。 “IN”运算符无法转换。“
你会看到我在修订表上有.DefaultIfEmpty()
。如果我删除执行分组的where (
代码,无论文档是否存在修订,我都会得到所需的结果。但是如果没有链接,where子句应该返回文档的最高版本号,如果不是,我仍然想要返回所有其他数据。与我的SQL代码不同,这不会发生。它只会返回有修订表链接的数据。
我希望这有点意义。 按代码分组是弄乱我的结果集的原因。无论是否有修订表的链接,我仍然希望我的结果返回。请帮忙!
感谢。
=======
我现在使用的代码感谢Gert。
var query = from p in db.Projects
from d in p.Documents
where p.ProjectID == Convert.ToInt32(Request.QueryString["projectId"])
select new
{
p.ProjectID,
d.DocumentNumber,
d.DocumentID,
d.DocumentTitle,
Status = d.Revisions
.OrderByDescending(rn => rn.RevisionID)
.FirstOrDefault().DocumentStatuse.Status,
RevisionNumber = d.Revisions
.OrderByDescending(rn => rn.RevisionID)
.FirstOrDefault().RevisionNumber
};
gvDocumentSelection.DataSource = query;
gvDocumentSelection.DataBind();
虽然这有效,但您会看到我通过运行相同的代码从修订表中选择两个字段,但选择了两个不同的字段。我猜有更好,更有效的方法来做到这一点?理想情况下,我想加入修订表,以防我需要访问更多字段,但之后我再次遇到相同的分组问题。
Status = d.Revisions
.OrderByDescending(rn => rn.RevisionID)
.FirstOrDefault().DocumentStatuse.Status,
RevisionNumber = d.Revisions
.OrderByDescending(rn => rn.RevisionID)
.FirstOrDefault().RevisionNumber
最终工作代码:
var query = from p in db.Projects
from d in p.Documents
where p.ProjectID == Convert.ToInt32(Request.QueryString["projectId"])
select new
{
p.ProjectID,
d.DocumentNumber,
d.DocumentID,
d.DocumentTitle,
LastRevision = d.Revisions
.OrderByDescending(rn => rn.RevisionID)
.FirstOrDefault()
};
var results = from x in query
select
new
{
x.ProjectID,
x.DocumentNumber,
x.DocumentID,
x.DocumentTitle,
x.LastRevision.RevisionNumber,
x.LastRevision.DocumentStatuse.Status
};
gvDocumentSelection.DataSource = results;
gvDocumentSelection.DataBind();
答案 0 :(得分:1)
如果你有1:n导航属性,有一种更简单(和推荐)的方法来实现这个目的:
from p in db.Projects
from d in p.Documents
select new { p, d,
LastRevision = d.Revisions
.OrderByDescending(r => r.RevisionId)
.FirstOrDefault() }
没有导航属性,它是相似的:
from p in db.Projects
join d in db.Documents on new { ProjectID = p.ProjectID }
equals new { ProjectID = Convert.ToInt32(d.ProjectID) }
select new { p, d,
LastRevision = db.Revisions
.Where(r => d.DocumentID = Convert.ToInt32(r.DocumentID))
.OrderByDescending(r => r.RevisionId)
.FirstOrDefault() }
修改强>
您可以使用各种投影修改此非常宽的基本查询,例如:
from x in query select new { x.p.ProjectName,
x.d.DocumentName,
x.LastRevision.DocumentStatus.Status,
x.LastRevision.FieldA,
x.LastRevision.FieldB
}