与LINQ和Lambda一起/在哪里


457

我遇到了用LINQ和Lambda编写的查询的麻烦。到目前为止,我的代码很多:

int id = 1;
var query = database.Posts.Join(database.Post_Metas,
                                post => database.Posts.Where(x => x.ID == id),
                                meta => database.Post_Metas.Where(x => x.Post_ID == id),
                                (post, meta) => new { Post = post, Meta = meta });

我是使用LINQ的新手,所以不确定此查询是否正确。


11
你想达到什么目的?
赫尔曼·罗德里格斯

4
您希望查询用句子做什么?
猎人

6
您的主要选择的方式太复杂了。如果要按ID选择,只需x => x.ID就可以了。
埃里克·利珀特

1
我想从数据库中获取一个帖子以及该帖子的元数据。
大卫2010年

Answers:


1053

我发现,如果您熟悉SQL语法,则使用LINQ查询语法会更清晰,更自然,并且更容易发现错误:

var id = 1;
var query =
   from post in database.Posts
   join meta in database.Post_Metas on post.ID equals meta.Post_ID
   where post.ID == id
   select new { Post = post, Meta = meta };

但是,如果您真的很喜欢使用lambda,那么您的语法就会有些偏离。这是使用LINQ扩展方法的相同查询:

var id = 1;
var query = database.Posts    // your starting point - table in the "from" statement
   .Join(database.Post_Metas, // the source table of the inner join
      post => post.ID,        // Select the primary key (the first part of the "on" clause in an sql "join" statement)
      meta => meta.Post_ID,   // Select the foreign key (the second part of the "on" clause)
      (post, meta) => new { Post = post, Meta = meta }) // selection
   .Where(postAndMeta => postAndMeta.Post.ID == id);    // where statement

10
@Emanuele Greco,关于您的编辑,“ ID字段上的相等性设置为JOIN条件;您无需使用WHERE子句!”:WHERE子句不是在测试ID字段之间的相等性,而是在测试帖子ID之间的相等性列和在查询外部声明的id参数。
丹尼尔·谢弗

9
令人敬畏的一部分, lambda引述易于使用和理解
Piotr Kula 2013年

1
令人敬畏的例子
玩具

1
有时对lambda的解释是用lambda编写的。很好解释。
捏住

80

您可以使用两种方法。使用LINQPad(如果您不熟悉 LINQ,这将是非常宝贵的)和一个虚拟数据库,我建立了以下查询:

Posts.Join(
    Post_metas,
    post => post.Post_id,
    meta => meta.Post_id,
    (post, meta) => new { Post = post, Meta = meta }
)

要么

from p in Posts
join pm in Post_metas on p.Post_id equals pm.Post_id
select new { Post = p, Meta = pm }

在这种情况下,我认为LINQ语法更简洁(我根据最容易阅读的内容在两者之间进行更改)。

我想指出的是,如果数据库中有适当的外键(在post和post_meta之间),那么除非您试图加载大量记录,否则可能不需要显式联接。 。您的示例似乎表明您正在尝试加载单个帖子及其元数据。假设每个帖子有很多post_meta记录,那么您可以执行以下操作:

var post = Posts.Single(p => p.ID == 1);
var metas = post.Post_metas.ToList();

如果要避免n + 1问题,则可以明确地告诉LINQ to SQL一次性加载所有相关项(尽管当您更熟悉L2S时,这可能是高级主题)。下面的示例说:“在加载帖子时,还通过'Post_metas'属性表示的外键加载与其相关的所有记录”:

var dataLoadOptions = new DataLoadOptions();
dataLoadOptions.LoadWith<Post>(p => p.Post_metas);

var dataContext = new MyDataContext();
dataContext.LoadOptions = dataLoadOptions;

var post = Posts.Single(p => p.ID == 1); // Post_metas loaded automagically

可以在同一类型或许多不同类型LoadWith的单个集合上进行多次调用DataLoadOptions。如果这样做很多,您可能只想考虑缓存。


1
LinqPad CRM 2016
Kiquenet '16

49

Daniel对语法关系有很好的解释,但是我将本文档放在一起给我的团队,以使他们更容易理解。希望这可以帮助某人在此处输入图片说明


当您仅处理像此处所示的值列表时,这将行不通。该对象上没有id属性。
Talspaugh18年

我确实发现这确实有用,但是出现了一个错误,要求我添加联接列。还要查看@Mark Byers发布的答案,联接列Post_ID的第二个别名为meta => meta.Post_ID。在此示例的示例中,g.id原始select语句的一部分JOIN gStatus g on g.id未在最终的Lambda表达式中复制。
SausageFingers

3
我并不是想将其发布为对OP发布所需的实际linq的引用,它更多是关于如何将SQL转换为Linq格式的引用,因此我的输入内容与原始问题略有不同。如果我为gStatus值创建了一个类,我会在其上放置一个id属性,然后是的,它将与g => g.id结合在一起,我使用了一个值列表来尝试使代码尽可能简单。
Talspaugh18年

@ Talspaugh27那么,为什么要在SQL查询中将其加入g.id上的gStatus?这是错误还是故意的?
Drammy

sql表中的@Drammy每列都必须有一个名称,因此,由于这是一个严格用于容纳这些ID的1列表,因此我只使用了一个名为id的列,因此List <int>没有这个问题。如果我是这样设置的, public class IdHolder{ int id } 然后在gStatus中使用了该对象, List<IdHolder> gStatus = new List<IdHolder>(); gStatus.add(new IdHolder(){id = 7}); gStatus.add(new IdHolder(){id = 8}); 那么它将改变Linq,t =>t.value.TaskStatusId, g=>g.id 这样的改变有意义吗?
Talspaugh27年

37

您的键选择器不正确。他们应该获取所涉及表类型的对象,并返回要在联接中使用的键。我想你的意思是:

var query = database.Posts.Join(database.Post_Metas,
                                post => post.ID,
                                meta => meta.Post_ID,
                                (post, meta) => new { Post = post, Meta = meta });

之后,您可以应用where子句,而不是作为键选择器的一部分。


9

发布是因为当我开始LINQ + EntityFramework时,我盯着这些示例看了一天。

如果您使用的是EntityFramework,并且MetaPost模型对象上设置了导航属性,那么这很容易。如果您使用的是实体但没有该导航属性,那么您还在等什么呢?

database
  .Posts
  .Where(post => post.ID == id)
  .Select(post => new { post, post.Meta });

如果您是先编写代码,则可以这样设置属性:

class Post {
  [Key]
  public int ID {get; set}
  public int MetaID { get; set; }
  public virtual Meta Meta {get; set;}
}

5

我已经做了这样的事情;

var certificationClass = _db.INDIVIDUALLICENSEs
    .Join(_db.INDLICENSECLAsses,
        IL => IL.LICENSE_CLASS,
        ILC => ILC.NAME,
        (IL, ILC) => new { INDIVIDUALLICENSE = IL, INDLICENSECLAsse = ILC })
    .Where(o => 
        o.INDIVIDUALLICENSE.GLOBALENTITYID == "ABC" &&
        o.INDIVIDUALLICENSE.LICENSE_TYPE == "ABC")
    .Select(t => new
        {
            value = t.PSP_INDLICENSECLAsse.ID,
            name = t.PSP_INDIVIDUALLICENSE.LICENSE_CLASS,                
        })
    .OrderBy(x => x.name);

4

可能是这样的

var myvar = from a in context.MyEntity
            join b in context.MyEntity2 on a.key equals b.key
            select new { prop1 = a.prop1, prop2= b.prop1};

1

1等于1两个不同的表联接

var query = from post in database.Posts
            join meta in database.Post_Metas on 1 equals 1
            where post.ID == id
            select new { Post = post, Meta = meta };

1

此linq查询应为您工作。它将获取所有具有帖子元的帖子。

var query = database.Posts.Join(database.Post_Metas,
                                post => post.postId, // Primary Key
                                meta => meat.postId, // Foreign Key
                                (post, meta) => new { Post = post, Meta = meta });

等效SQL查询

Select * FROM Posts P
INNER JOIN Post_Metas pm ON pm.postId=p.postId

您关闭了括号,在第三个参数之后...“对于Join,没有重载需要三个参数”
LastTribunal

3
这与已接受的答案相同,并且在7年后-1
reggaeguitar
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.