使 LINQ 查询更好

7

我在使用LINQ语法时遇到了一些困难。有什么更好的方法来执行这个命令吗?

var user = (from u in context.users
            where u.email.Equals(email)
            select u).Single();
var pinToUser = (from ptu in context.pintousers
                 where ptu.user_id.Equals(user.id)
                 select ptu).Single();
var pin = (from p in context.pins
           where p.idpin.Equals(pinToUser.pin_idpin)
           select p).Single();

return pin;

正如您所看到的,有一个用户表,一个用户与PIN表之间的引用表和一个PIN表。 用户与PIN之间的引用表参考了用户表和PIN表。是否可以简短地写成"user.pintouser.pin"?我认为我已经设置好了所有的导航属性,但我不确定如何正确使用它们,或者通过修改它们来使它们更好。
谢谢阅读。

你可能可以将这个重写为一个单一的查询。 - leppie
4个回答

8
使用连接将所有内容重写为一个简洁的查询。如果我正确地阅读了您的查询,这应该可以给您正确的结果:
var pin = (from u in context.users
          join ptu in context.pintousers on u.id equals ptu.user_id
          join p in context.pins on ptu.pin_idpin equals p.idpin
          where u.email == email
          select p).Single();

请记住,如果此查询返回的结果不是单个结果,则您的代码将抛出异常。

如果您想处理获取一行或零行的可能性,那么您应该使用SingleOrDefault()

如果您想处理获取任意数量行的可能性,那么您应该使用FirstOrDefault()


@recursive - 你是对的,我太关注连接了,忘了调用Single()。已修复。 - Justin Niessner
1
我认为应该是"context.pins on ptu.pin_idpin equals p.idpin"。在你的例子中,它们是相反的。 - Phil
1
@Phil - 在指定连接条件时,顺序并不重要。它可以以任何方式编写。 - Justin Niessner
1
@Justin - 我实际上不得不在 VS 中更改它,因为它抱怨那样它们是没有上下文的。当我改变顺序时它就可以工作了?也许这与其他事情有关。 - Phil
@Phil - 有趣。我更新了答案,但我不知道为什么会引起问题。 - Justin Niessner
显示剩余2条评论

3
请注意,如果您在数据库中正确设置了外键关系,则Linq-to-Sql应该会自动为您执行联接操作:
var pin = (from u in context.users 
      where u.email == email 
      select u.pintouser.pin).Single(); 

这意味着您可以将其简化为:
var pin = context.users.Where(u=>u.email == email)
                       .Select(u=>u.pintouser.pin)
                       .Single();

(更新注:我最初建议的以下方法更简短,但我认为它会导致两次数据库往返)
var pin = context.users.Single(u=>u.email == email).Single().pintouser.pin;

现在,.pintouser.pin是安全的,因为Single()将始终返回一个user对象(或抛出异常)。

2

正如@JustinNiessner所指出的那样,你应该使用join,但这是另一种编写查询的方式。

var user = context.users.Single(u => u.email == email);
var pinToUser = context.pintousers.Single(ptu => ptu.user_id == user.id);
var pin = context.pins.Single(p => p.idpin == pinToUser.pin_idpid);

1

既然您有导航属性,不妨使用它们:

Pin pin =
(
  from u in context.Users
  where u.email == email
  from ptu in u.pintousers
  let p = ptu.pin
  select p
).Single();

正如你可能在循环内声明一个变量,为每次循环迭代创建一个变量... "let" 允许你为查询中的每一行声明一个变量。 - Amy B

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接