我在使用 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 };
但是,如果您真的坚持使用 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
你可以有两种方法。使用 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
可以针对同一类型或许多不同类型对一组 DataLoadOptions
进行多次 LoadWith
调用。如果你做了很多,你可能只想考虑缓存。
https://i.stack.imgur.com/rqfoa.png
meta => meta.Post_ID
中有 Post_ID
字段。在此插图的示例中,原始选择语句 JOIN gStatus g on g.id
的 g.id
部分未在最终 Lambda 表达式中复制。
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
这种更改有意义吗?
您的键选择器不正确。他们应该获取相关表类型的对象并返回要在连接中使用的键。我想你的意思是:
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
的导航属性,那么这很容易。如果您正在使用实体并且没有导航属性,您还在等什么?
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 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);
这个 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
可能是这样的
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 连接的查询语法
var productOrderQuery = from product in Product.Setup()//outer sequence
join order in OrderDetails.Setup()//inner sequence
on product.Id equals order.ProductId //key selector
select new//result selector
{
OrderId = order.Id,
ProductId = product.Id,
PurchaseDate = order.PurchaseDate,
ProductName = product.Name,
ProductPrice = product.Price
};
LINQ 连接的方法语法
var productOrderMethod = Product.Setup().//outer sequence
Join(OrderDetails.Setup(), //inner sequence
product => product.Id//key selector
,order=> order.ProductId //key selector
,(product,order)=> //projection result
new
{
OrderId = order.Id,
ProductId = product.Id,
PurchaseDate = order.PurchaseDate,
ProductName = product.Name,
ProductPrice = product.Price
}
);
Product.cs 供参考
class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public static IEnumerable<Product> Setup()
{
return new List<Product>()
{
new Product(){Id=1, Name="Bike", Price=30.33M },
new Product(){Id=2, Name="Car", Price=50.33M },
new Product(){Id=3, Name="Bus", Price=60.33M }
};
}
}
OrderDetails.cs 类供参考
class OrderDetails
{
public int Id { get; set; }
public virtual int ProductId { get; set; }
public DateTime PurchaseDate { get; set; }
public static IEnumerable<OrderDetails> Setup()
{
return new List<OrderDetails>()
{
new OrderDetails(){Id=1, ProductId=1, PurchaseDate= DateTime.Now },
new OrderDetails(){Id=2, ProductId=1, PurchaseDate=DateTime.Now.AddDays(-1) },
new OrderDetails(){Id=3, ProductId=2, PurchaseDate=DateTime.Now.AddDays(-2) }
};
}
}
等于 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 };
lambda
的精彩片段,引文易于使用和理解