切换linq语法

时间:2010-05-24 15:44:11

标签: c# linq

 var folders = from r in this.bdd.Rights
               join f in this.bdd.Folders on r.RightFolderId equals f.FolderId
               join rs in this.bdd.RightSpecs on r.RightSpecId equals rs.SpecIdRight
               where r.RightUserId == userId
               where rs.SpecRead == true
               where rs.SpecWrite == true
               select f;

如何在其他语法中转换此linq查询?

 var folders = this.bdd.Rights.Where(r => r.....

3 个答案:

答案 0 :(得分:9)

阅读C#4规范中的第7.16.2节。所有规则都在那里。

让我们来看看吧。你有:

from r in this.bdd.Rights 
join f in this.bdd.Folders on r.RightFolderId equals f.FolderId 
join rs in this.bdd.RightSpecs on r.RightSpecId equals rs.SpecIdRight 
where r.RightUserId == userId 
where rs.SpecRead == true 
where rs.SpecWrite == true 
select f; 

规范说

  

带有join子句的查询表达式,其中没有into后跟select子句

之外的其他内容
from x1 in e1
join x2 in e2 on k1 equals k2 
...
  

被翻译成

from * in ( e1 ) 
. Join(e2 , x1 => k1 , x2 => k2 , ( x1 , x2 ) => new { x1 , x2 })
...

好的,我们首先将您的查询翻译成

from * in 
(this.bdd.Rights)
.Join(
    this.bdd.Folders, 
    r=>r.RightFolderId, 
    f=>f.FolderId, 
    (*, f)=> new {r, f})
join rs in this.bdd.RightSpecs on r.RightSpecId equals rs.SpecIdRight 
where r.RightUserId == userId 
where rs.SpecRead == true 
where rs.SpecWrite == true 
select f; 

现在再次适用相同的规则;我们有一个带有join子句的查询表达式,没有into后跟select之外的其他东西。这就变成了:

from ** in 
((this.bdd.Rights)
.Join(
    this.bdd.Folders, 
    r=>r.RightFolderId, 
    f=>f.FolderId, 
    (r, f)=> new {r, f}))
.Join(
    this.bdd.RightSpecs,
    *=>r.RightSpecId,
    rs=>rs.SpecIdRight,
    (*, rs)=> new {*, rs})
where r.RightUserId == userId 
where rs.SpecRead == true 
where rs.SpecWrite == true 
select f; 

适用的下一条规则是什么?参考规范:

  

带有where子句

的查询表达式
from x in e
where f
...
  

被翻译成

from x in ( e ) . Where ( x => f )
...

好的,我们应用该转换三次并获得

from ** in 
(((((this.bdd.Rights)
.Join(
    this.bdd.Folders, 
    r=>r.RightFolderId, 
    f=>f.FolderId, 
    (r, f)=> new {r, f}))
.Join(
    this.bdd.RightSpecs,
    *=>r.RightSpecId,
    rs=>rs.SpecIdRight,
    (*, rs)=> new {*, rs}))
.Where(**=>r.RightUserId == userId ))
.Where(**=>rs.SpecRead == true))
.Where(**=>rs.SpecWrite == true)
select f; 

现在怎样?参考规范:

from x in e select v
  

被翻译成

( e ) . Select ( x => v )

所以上面的代码被翻译成

((((((this.bdd.Rights)
.Join(
    this.bdd.Folders, 
    r=>r.RightFolderId, 
    f=>f.FolderId, 
    (r, f)=> new {r, f}))
.Join(
    this.bdd.RightSpecs,
    *=>r.RightSpecId,
    rs=>rs.SpecIdRight,
    (*, rs)=> new {*, rs}))
.Where(**=>r.RightUserId == userId ))
.Where(**=>rs.SpecRead == true))
.Where(**=>rs.SpecWrite == true))
.Select(**=>f);

其中***是透明标识符。所以这会进一步转化为

((((((this.bdd.Rights)
.Join(
    this.bdd.Folders, 
    r=>r.RightFolderId, 
    f=>f.FolderId, 
    (r, f)=> new {r, f}))
.Join(
    this.bdd.RightSpecs,
    t1=>t1.r.RightSpecId,
    rs=>rs.SpecIdRight,
    (t1, rs)=> new {t1, rs}))
.Where(t2=>t2.t1.r.RightUserId == userId ))
.Where(t2=>t2.rs.SpecRead == true))
.Where(t2=>t2.rs.SpecWrite == true))
.Select(t2=>t2.t1.f);

我们在那里引入了许多不必要的括号。我们可以把它们拿出来说这相当于

this.bdd.Rights
.Join(
    this.bdd.Folders, 
    r=>r.RightFolderId, 
    f=>f.FolderId, 
    (r, f)=> new {r, f})
.Join(
    this.bdd.RightSpecs,
    t1=>t1.r.RightSpecId,
    rs=>rs.SpecIdRight,
    (t1, rs)=> new {t1, rs})
.Where(t2=>t2.t1.r.RightUserId == userId )
.Where(t2=>t2.rs.SpecRead == true)
.Where(t2=>t2.rs.SpecWrite == true)
.Select(t2=>t2.t1.f);

容易腻。除了对透明标识符的一些分析之外,它只是一个简单的语法重写。

答案 1 :(得分:7)

老实说,当谈到使用Joins时,我坚持使用Query语法。

该查询的Lambda语法将不可读。

不幸的是我现在没有时间输入转换,所以我建议你下载LINQPad。它允许您使用Query语法并查看Lambda转换以及生成的SQL。

Download LINQPad

所以......我决定试一下练习代码。我认为它看起来像:

var folders = this.bdd.Rights
                  .Join(this.bdd.Folders,
                        r => r.RightFolderId,
                        f => f.FolderId,
                        (r,f) => new { Outer = r, Inner = f })
                  .Join(this.bdd.RightSpecs,
                        r => r.Outer.RightSpecId,
                        rs => rs.SpecIdRight,
                        (r,rs) => new { Outer = r, Inner = rs })
                  .Where(r => r.Outer.Outer.RightUserId == userId)
                  .Where(r => r.Inner.SpecRead == true)
                  .Where(r => r.Inner.SpecWrite == true)
                  .Select(r => r.Outer.Inner);

就像我说的,这是为了练习,所以我不能100%确定它是否正确它绝对可以让你知道为什么你可能要考虑保持查询语法。

答案 2 :(得分:0)

如果在LinqToSql设计器中添加这些项的关联,您将获得导航属性。这些属性使编写查询更容易,而不必担心加入概念。

我会重写原始查询以从连接中删除重复。您需要过滤文件夹查询,因此请编写一个过滤文件夹的查询。

var folderQuery =
  from f in this.bdd.Folders
  where f.Rights.Any(r => r.RightUserId = userId &&
    r.RightSpecs.Any(rs => rs.SpecRead && rs.SpecWrite))
  select f;

然后将其翻译成:

var folderQuery = this.bdd.Folders
  .Where(f => f.Rights.Any(r => r.RightUserId = userId &&
    r.RightSpecs.Any(rs => rs.SpecRead && rs.SpecWrite));