【问题标题】:Left outer join using LINQ Query Syntax EF Core C#使用 LINQ 查询语法 EF Core C# 的左外连接
【发布时间】:2021-08-25 20:47:41
【问题描述】:

我有一个关于以下问题的问题,

  1. 未通过外键连接的两个表的左外连接。
  2. 按第二个表中匹配的结果排序。
  3. 我希望在 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;
}

【问题讨论】:

    标签: c# sql entity-framework linq asp.net-core


    【解决方案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 不要注册加载的实体。如果您没有获得记录,只需 CountAny 等 - 所以没有任何更改跟踪。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-06
    • 1970-01-01
    • 2019-03-27
    • 2013-05-26
    • 2011-04-29
    • 2023-03-19
    • 1970-01-01
    相关资源
    最近更新 更多