C#joinLinq和Lambda
用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的新手,所以我不确定这个查询是否正确。
我发现,如果您熟悉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 };
如果你真的坚持使用lambdaexpression式,那么你的语法就差了很多。 以下是使用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
你可以用这两种方法。 使用LINQPad (如果你是LINQ的新手,这是非常宝贵的)和一个虚拟数据库,我build立了以下查询:
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之间),那么除非你想加载大量的logging,否则你可能不需要显式的连接。 你的例子似乎表明你正试图加载一个单一的职位,它的元数据。 假设每个post都有很多post_metalogging,那么您可以执行以下操作:
var post = Posts.Single(p => p.ID == 1); var metas = post.Post_metas.ToList();
如果你想避免n + 1问题,那么你可以明确地告诉LINQ to SQL一次加载所有相关的项目(虽然这可能是一个高级的话题,当你更熟悉L2S)。 下面的例子说:“当你加载一个post时,也通过'Post_metas属性'代表的外键加载它的所有相关logging:
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
对于同一types或多种不同的types,可以在一组DataLoadOptions
上进行多个LoadWith
调用。 如果你这么做,你可能只想考虑caching。
你的关键select器是不正确的。 他们应该采取有关表的types的对象,并返回在连接中使用的密钥。 我认为你的意思是:
var query = database.Posts.Join(database.Post_Metas, post => post.ID, meta => meta.Post_ID, (post, meta) => new { Post = post, Meta = meta });
之后可以应用where子句,而不是作为键select器的一部分。
丹尼尔对语法关系有很好的解释,但是我把这个文档放在一起,以便让我们的团队更容易理解。 希望这有助于某人
发帖是因为当我开始LINQ + EntityFramework时,我盯着这些例子一天。
如果您使用的是EntityFramework,并且您的Post
模型对象上已经有一个名为Meta
的导航属性,这很容易。 如果您使用实体并且没有该导航属性,那么您还在等什么?
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;} }
这可能是类似的东西
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};
这个linq查询应该为你工作。 它会得到所有后期的meta。
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
我做了这样的事情;
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);