使用 LINQ 查询语法 EF Core C# 的左外连接
Posted
技术标签:
【中文标题】使用 LINQ 查询语法 EF Core C# 的左外连接【英文标题】:Left outer join using LINQ Query Syntax EF Core C# 【发布时间】:2021-08-25 20:47:41 【问题描述】:我有一个关于以下问题的问题,
-
未通过外键连接的两个表的左外连接。
按第二个表中匹配的结果排序。
我希望在 LINQ 查询方法语法中完成此操作,因为我根据提供的输入以及跳过和限制添加了许多条件。
如果我们有以下产品和收藏表
所以我想要的输出是:
意思是最喜欢的作为第一组的一部分,而不是最喜欢的应该放在他们后面。以下是我所做的尝试。 我能够加入表格获取输出,但不确定如何确保在第一页中获得所有收藏。
这个答案非常接近我的想法,但它得到了结果,然后进行了排序,这在我的情况下是不可能的,因为我正在进行分页并使用 IQueryable 来获取更少的数据。
Group Join and Orderby while maintaining previous query
对任何解决方案持开放态度以实现相同目标。
[Table("Product")]
public class ProductModel
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid ProductId get; set;
public string ProductName get; set;
public bool IsFavorite get; set;
[Table("UserFavorite")]
public class UserFavoriteModel
[Required]
public Guid UserId get; set;
[Required]
public Guid Identifier get; set;
[Required]
public FavoriteType Type get; set;
// Gets products
private async Task<List<ProductModel>> GetProductsAsync(
Guid categoryId,
Guid subCategoryId,
int from,
int limit)
var query = _context.Products.AsQueryable();
if (!string.IsNullOrEmpty(categoryId))
query = query.Where(product => product.CategoryId == categoryId);
if (!string.IsNullOrEmpty(subCategoryId))
query = query.Where(product => product.SubCategoryId == subCategoryId);
query = query.Skip(from).Take(limit);
var products = await query.ToListAsync();
query = query.GroupJoin(
_context.Favorites.AsNoTracking()
.Where(favorite => favorite.Type == FavoriteType.FASHION)
// This user Id will come from context just adding for overall picture.
.Where(favorite => favorite.UserId == userId),
//This orderby if I add will not make any difference.
//.OrderByDescending(favorite => favorite.Identifier),
v => v.ProductId,
f => f.Identifier,
(product, fav) => new product, fav ).
SelectMany(x => x.Fav.DefaultIfEmpty(),
(x, y) => SetFavorite(x.Project, y));
private static ProductModel SetFavorite(ProductModel v, UserFavoriteModel si)
v.IsFavorite = (si != null);
return v;
【问题讨论】:
【参考方案1】:我会这样做:
var query =
_context.Products.AsQueryable().Select(p => new ProductModel
ProductId = p.ProductId,
ProductName = p.ProductName,
IsFavorite =
_context.Favorites.Any(f =>
f.Identifier = p.ProductId &&
f.Type == FavoriteType.FASHION &&
f.UserId == userId
)
).OrderByDescending(favorite => favorite.Identifier);
【讨论】:
AsNoTracking 内部投影且不返回记录 - 对我来说是新事物;) @Aducci 非常感谢。这看起来比我想象的要简单,要学习很多:)。有一些错别字可能对其他人有用 f.Identifier = p.ProductId(这应该有 ==),并且 order 应该是 OrderByDescending(favorite => favorite.IsFavorite)。如果我在 ProductModel 中有大量字段,我有一个小小的说明,是否有一种方法可以简化它而不是在选择中声明所有字段。我试过 Select(p => p.IsFavorite =favs condition here ; return p;) 但我想这在 Expressions 中不受支持。 @SvyatoslavDanyliv 我只是用这个方法在 SO 中发布并忘记添加返回部分:)。据我了解,AsNoTracking 仅用于读取,我什至将其用于 _context.Products.AsNoTracking,是否有我不应该使用的原因。是因为 IQueryable?AsNoTracking
用于“通知”ChangeTracker 不要注册加载的实体。如果您没有获得记录,只需 Count
或 Any
等 - 所以没有任何更改跟踪。以上是关于使用 LINQ 查询语法 EF Core C# 的左外连接的主要内容,如果未能解决你的问题,请参考以下文章