【问题标题】:Entity Framework: Load data from different tables in one query实体框架:在一个查询中从不同的表中加载数据
【发布时间】:2021-03-22 17:12:48
【问题描述】:

在我使用 EF Core 5.0 的 C# 项目中,我有几个独立的表:ClothesHairsMakeup。他们的一些列是相似的,但有些不是..` 我需要编写一个从这些表中加载行的方法。我现在拥有的是:

public async Task<(ClothesDbModel[] clothes, MakeupDbModel[] makeups, HairDbModel[] hairs)> GetDressup(int[] clothesIds, int[] makeupIds, int[] hairIds)
{
    ClothesDbModel[] clothes = new ClothesDbModel[0];
    if (clothesIds.Length > 0)
    {
        clothes = await _dbContext.Clothes.Where(c => clothesIds.Contains(c.Id)).ToArrayAsync();
    }

    MakeupDbModel[] makeups = new MakeupDbModel[0];
    if (makeupIds.Length > 0)
    {
        makeups = await _dbContext.Makeups.Where(c => makeupIds.Contains(c.Id)).ToArrayAsync();
    }

    HairDbModel[] hairs = new HairDbModel[0];
    if (hairIds.Length > 0)
    {
        hairs = await _dbContext.Hairs.Where(c => hairIds.Contains(c.Id)).ToArrayAsync();
    }

    return (clothes, makeups, hairs);
}

但是,在这种情况下,我对数据库有 3 个单独的查询(3 个等待)。从性能的角度来看,我认为这不是加载数据的最佳方式。也许我只能使用 DbContext 加载相同的数据一次&

【问题讨论】:

  • 如果这些表互不依赖,那就没有办法了
  • 您可能知道 EF 不支持 multiple parallel operations。您可以创建三个不同的_dbContext。但是,由于开销可能不值得。
  • 实际上可以使用Concat 做到这一点,但需要在客户端进行后处理。

标签: c# entity-framework-core


【解决方案1】:

我希望它可以与 EF 一起使用。但是我知道 Concat 有问题,所以它可能会失败。

class CombinedResult
{
    public ClothesDbModel Clothes;
    public MakeupDbModel Makeup;
    public HairDbModel Hair;
}

...

public async Task<(ClothesDbModel[] clothes, MakeupDbModel[] makeups, HairDbModel[] hairs)> GetDressup(int[] clothesIds, int[] makeupIds, int[] hairIds)
{
    var queries = new List<IQueryable<CombinedResult>>();

    if (clothesIds.Length > 0)
    {
        queries.Add(_dbContext.Clothes.Where(c => clothesIds.Contains(c.Id)).Select(c => new CombinedResult { Clothes = c }));
    }

    if (makeupIds.Length > 0)
    {
        queries.Add(_dbContext.Makeups.Where(c => makeupIds.Contains(c.Id)).Select(c => new CombinedResult { Makeup = c }));
    }

    if (hairIds.Length > 0)
    {
        queries.Add(_dbContext.Hairs.Where(c => hairIds.Contains(c.Id)).Select(c => new CombinedResult { Hair = c }));
    }

    var clothes = new List<ClothesDbModel>();
    var makeups = new List<MakeupDbModel>();
    var hairs = new List<HairDbModel>();

    if (queries.Count > 0)
    {
        var query = queries[0];
        for (var i = 1; i < queries.Count; i++)
        {
            query = query.Concat(queries[i]);
        }

        var items = await query.ToListAsync();
        foreach (var item in items)
        {
            if (item.Clothes != null)
                clothes.Add(item.Clothes);
            else if (item.Makeup != null)
                makeups.Add(item.Makeup);
            else if (item.Hair != null)
                hairs.Add(item.Hair);
        }
    }

    return (clothes.ToArray(), makeups.ToArray(), hairs.ToArray());
}

【讨论】:

  • 我得到了以下异常Unable to translate set operation when both sides don't assign values to same properties in the nominal type. Please make sure that the properties are inclued on both sides, consider assigning default value if the property doesn't require a specific value. 所以,我用空值初始化了 CombinedResult 的缺失属性。但是,在那之后,我遇到了另一个可能可以修复的异常Unable to translate set operation after client projection has been applied. Consider moving the set operation before the last 'Select' call.
  • 很高兴知道,所以忘记 EF 和普通的Concat 查询。无论如何,这个扩展将运行这样的查询:github.com/linq2db/linq2db.EntityFrameworkCore
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-10
  • 2021-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多