【问题标题】:Linq2db: effective way to query hierarchy of objectsLinq2db:查询对象层次结构的有效方法
【发布时间】:2020-11-18 21:10:14
【问题描述】:

我正在使用 c# 和 linq2db,并具有以下类/表层次结构:

public class YearlyTemplate
{
    [Column]
    public int Id { get; set; }
    public List<MonthlyTemplate> MonthlyTemplates { get; set;}
}

public class MonthlyTemplate
{
    [Column]
    public int Id { get; set; }

    [Column]
    public int YearlyTemplateId { get; set; }

    public YearlyTemplate YearlyTemplate{ get; set; }

    public List<DailyTemplate> DailyTemplates { get; set;}
}

public class DailyTemplate
{
    [Column]
    public int Id { get; set; }

    [Column]
    public int MonthlyTemplateId { get; set; }
    
    public MonthlyTemplate MonthlyTemplate { get; set; }
}

public class AppDataConnect : DataConnection
{
    public ITable<YearlyTemplate> YearlyTemplates => GetTable<YearlyTemplate>();
    public ITable<WeeklyTemplate> WeeklyTemplates => GetTable<WeeklyTemplate>();
    public ITable<DailyTemplate>  DailyTemplates => GetTable<DailyTemplate>();
}

我想使用 where 语句从数据库中获取特定年份,但我想获取所有嵌套的 MonthlyTemplates 以及每个 Monthlytemplate 的所有 DailyTemplates。 如何有效地使用 linq2db? 我想我应该使用 group by,但它只适用于一级深度。

【问题讨论】:

  • ORM 是一个有漏洞的抽象,这也是漏洞之一——ORM 不能很好地处理报告查询,因为它无论如何都不能处理对象/实体。通常,此类问题可以通过使用日历表来解决,即具有例如 20 年日期的表,其中重新填充了索引覆盖的年、月、日、季度、学期字段。要查找特定时期的记录,您可以加入日历表并按您想要的年份或月份进行过滤。棘手的查询变成了对索引列的单个连接和过滤
  • 日历表虽然是一个辅助表,但出现在应用程序的数据或域模型中通常没有意义。您可以添加它,只是为了使查询更容易,或者您可以在使用日历表的数据库中创建一个视图/存储过程并将结果映射到您的数据模型
  • 日期在哪里?如果没有日期,你怎么知道哪一天是哪一天?你想要的是选择很多,但没有日期它是行不通的。
  • 日期字段不是这样的。我们不需要它;提供的层次结构只是原始层次结构的简化示例。所以,我们不需要关心日期,这就是为什么我也不能使用日历。
  • 我使用这样的东西:var results = db_context.YearlyTemplate.SelectMany(x => x.MonthlyTemplates.SelectMany(y => y.DailyTemplates.Select(z => new { yearlyID = x. Id,monthlyID = y.Id,dailyId = z.Id}))).ToList();

标签: c# postgresql linq2db


【解决方案1】:

这里没什么特别的。就像在 EF Core 中一样,linq2db 包含用于急切加载的方法。 首先你必须定义关联

public class YearlyTemplate
{
    [Column]
    public int Id { get; set; }

    [Association(ThisKey = nameof(YearlyTemplate.Id), OtherKey = nameof(MonthlyTemplate.YearlyTemplateId))]
    public List<MonthlyTemplate> MonthlyTemplates { get; set;}
}

public class MonthlyTemplate
{
    [Column]
    public int Id { get; set; }

    [Column]
    public int YearlyTemplateId { get; set; }

    public YearlyTemplate YearlyTemplate{ get; set; }

    [Association(ThisKey = nameof(MonthlyTemplate.Id), OtherKey = nameof(DailyTemplate.MonthlyTemplateId))]
    public List<DailyTemplate> DailyTemplates { get; set;}
}

并查询

var query = 
  from y in db.YearlyTemplates
           .LoadWith(yt => yt.MonthlyTemplates)
              .ThenLoad(mt => mt.DailyTemplates)
  where y.Id == 1
  select y;

var result = query.ToArray();

或者带过滤器(自定义LoadWith/ThenLoad的两种方式)

var query = 
  from y in db.YearlyTemplates
           .LoadWith(yt => yt.MonthlyTemplates.Where(mt => !mt.IsDeleted))
              .ThenLoad(mt => mt.DailyTemplates, q => q.Where(ti => !dt.IsDeleted))
  where y.Id == 1
  select y;

var result = query.ToArray();

或者您可以使用自定义投影,因为您可以只选择需要的字段,因此性能会更高:

var query = 
  from y in db.YearlyTemplates
  where y.Id == 1
  select new 
  {
     Id = y.Id,
     MonthlyTemplates = y.MonthlyTemplates.Select(mt => new {
        mt.Id,
        DailyTemplates = mt.DailyTemplates.ToArray()
     }).ToArray()
  };

var result = query.ToArray();

【讨论】:

  • 谢谢。您的答案是我正在寻找的评论。在 linq2db 文档中找到这样一个典型的功能并不容易。我不知道为什么。
  • 您知道我是否可以在您的示例中过滤 DailyTemplates 吗?我不想从数据库中获取所有这些,而只是从过滤后的部分中获取。
  • 使用过滤器更新帖子。关于文档:需要志愿者。
  • 在这种情况下是否可以加入 MonthlyTemplate ?我想做这样的事情:从 db.YearlyTemplates.LoadWith(yt => yt.MonthlyTemplates.LeftJoin(t => t.AnotherTableId == AnotherTable.Id)中的 y
  • 是的,这是可能的,但最好创建新问题。答案将作为参考来源。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-02
  • 2020-04-17
  • 2015-10-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多