如何在我的LINQ中实现对数据库的单次调用

本文关键字:数据库 单次 调用 实现 我的 LINQ | 更新日期: 2023-09-27 18:20:33

我正在进行我的web API项目。

我在控制器类中有一行LinqToEntity

SiteObject[] objects = await ObjectsRepository.Get().Where(x => x.SiteRegionId == regionId).ToArrayAsync();
return Ok(objects.Select(x => new ObjectBreif
    {
        IsServiceable = Context.InspectionReview.Any(i => i.ObjectId == x.Id && i.IsNormal == false) ? false : Context.InspectionReview.Any(i => i.ObjectId == x.Id) ? true : (bool?)null 
    })

我想创建比上面的行更有效的东西,而不是做两次数据库调用。

如果InspectionReview表中存在至少一行满足此条件条件:

ObjectId = 5 AND  IsNormal = false 

我需要将IsServiceable设置为false,否则,我需要检查InspectionReview表中是否存在具有以下条件的行:

 ObjectId = 5

如果是,则IsServiceable必须得到true,否则为null

我通过使用上面的一行代码实现了这一点。但正如您所看到的,它并没有效果,因为我访问了两次数据库。

我不想为这个提议或额外的行创建额外的函数,因为我希望代码保持优雅。

如何在我的LINQ中实现对数据库的单次调用

试试这个:

var items = Context.InspectionReview.Where(i => i.ObjectID == x.id).ToList();
bool? IsServicable = (items.length == 0) ? 
                     (bool?)null : !(items.Any(i => i.IsNormal == false));

知道代码中的objects是什么很重要,但无论如何,现在开始:

带子查询

var result =
    from x in objects
    let AnyNormal = db.InspectionReview.Where(r => r.ObjectId == x.Id)
        .DefaultIfEmpty().Min(r => r == null ? (int?)null : r.IsNormal ? 1 : 0)
    select new ObjectBreif
    {
        IsServiceable = AnyNormal == null ? (bool?)null : AnyNormal == 1
    };

或带有左侧外部连接

var result =
    from x in objects
    join r in db.InspectionReview on x.Id equals r.ObjectId into g
    let AnyNormal = g.DefaultIfEmpty().Min(r => r == null ? (int?)null : r.IsNormal ? 1 : 0)
    select new ObjectBreif
    {
        IsServiceable = AnyNormal == null ? (bool?)null : AnyNormal == 1
    };

更新::现在,当您更新代码片段时,如果ObjectsRepository.Get从数据库返回IQueryable<SiteObject>(没有提前具体化),那么最好将两个查询组合成一个单独的查询,如

var result =
    from x in ObjectsRepository.Get() where x.SiteRegionId == regionId
    join r in db.InspectionReview on x.Id equals r.ObjectId into g
    let AnyNormal = g.DefaultIfEmpty().Min(r => r == null ? (int?)null : r.IsNormal ? 1 : 0)
    select new ObjectBreif
    {
        IsServiceable = AnyNormal == null ? (bool?)null : AnyNormal == 1
    };

因为它将生成一个数据库查询,而所有其他数据库查询将对objects数组中的每个项执行(好的,单个,而不是原始查询的两倍)查询

编辑:由于ObjectId不是唯一的:

var grouped = (from ir in Context.InspectionReview
group ir by ir.ObjectId into g
select new {
              ObjectId = g.Key, 
              FalsePresent = g.Any(gg=>gg.IsNormal == false)}).FirstOrDefault();
if(grouped == null) return (bool?)null;
return !grouped.FalsePresent;

先按ObjectID筛选,然后优先选择IsNormal为false的:

var first = Context.InspectionReview
    .Where(i => i.ObjectId == x.Id)
    .OrderBy(i => IsNormal)
    .FirstOrDefault();
bool? IsServiceable = (first == null) ? (bool?)null : first.IsNormal;