关于c#:加入/ LINQ和Lambda的位置

Join/Where with LINQ and Lambda

我在使用Linq和lambda编写的查询中遇到问题。到目前为止,我有很多错误,这是我的代码:

1
2
3
4
5
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,所以我不确定这个查询是否正确。


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

1
2
3
4
5
6
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扩展方法:

1
2
3
4
5
6
7
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


你可以用这两种方法。我使用LinqPad(如果您是Linq新手的话,这是非常宝贵的)和一个虚拟数据库构建了以下查询:

1
2
3
4
5
6
Posts.Join(
    Post_metas,
    post => post.Post_id,
    meta => meta.Post_id,
    (post, meta) => new { Post = post, Meta = meta }
)

1
2
3
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记录,那么可以执行以下操作:

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

如果您想避免n+1问题,那么可以显式地告诉Linq to SQL一次性加载所有相关项(尽管这可能是您更熟悉L2时的高级主题)。下面的示例说"当您加载一个日志时,还可以通过"post-metas"属性表示的外键加载与其关联的所有记录:

1
2
3
4
5
6
7
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

可以对同一类型或多个不同类型的一组DataLoadOptions进行多个LoadWith调用。如果你做了很多,你可能只想考虑缓存。


您的按键选择器不正确。它们应该获取相关表类型的对象,并返回要在联接中使用的键。我认为你的意思是:

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

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


丹尼尔对语法关系有一个很好的解释,但是我把这个文档放在一起,以便我的团队能够更简单地理解它。希望能帮上忙


发布是因为当我启动Linq+EntityFramework时,我盯着这些示例看了一天。

如果您使用的是EntityFramework,并且在您的Post模型对象上设置了名为Meta的导航属性,那么这非常简单。如果您使用的是实体,并且没有该导航属性,那么您在等待什么?

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

如果你是先做代码,你就要设置这个属性:

1
2
3
4
5
6
class Post {
  [Key]
  public int ID {get; set}
  public int MetaID { get; set; }
  public virtual Meta Meta {get; set;}
}

我做过这样的事;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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);


可能有点像

1
2
3
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
2
3
4
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 };

这个LINQ查询应该对您有效。它将得到所有有post meta的帖子。

1
2
3
4
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查询

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