EF6中预加载关联数据获取指定TariffaOrariaLivello的优化方案
问题背景
我拥有如下实体模型类:
public class ClasseBase { // 其他属性 public EnumStato Stato { get; set; } } public class Gruppo : ClasseBase { public int Id { get; set; } // 其他属性 public virtual ICollection<Livello> Livelli { get; set; } } public class Livello : ClasseBase { public int Id { get; set; } // 其他属性 public byte Progressivo { get; set; } [ForeignKey(nameof(Gruppo))] public int IdGruppo { get; set; } public Gruppo Gruppo { get; set; } public virtual ICollection<TariffaOrariaLivello> TariffeOrarie { get; set; } } public class TariffaOrariaLivello { public int Id { get; set; } [ForeignKey("Livello")] public int IdLivello { get; set; } public Livello Livello { get; set; } [DataType(DataType.Currency)] public decimal StraordinarioDiurno { get; set; } [DataType(DataType.Currency)] public decimal StraordinarioNotturno { get; set; } [DataType(DataType.Currency)] public decimal StraordinarioFestivoNotturno { get; set; } [DataType(DataType.Date)] public DateTime DataInizio { get; set; } [DataType(DataType.Date)] public DateTime? DataFine { get; set; } }
对应的DbContext定义如下:
public DbSet<Livello> Livelli { get; set; } public DbSet<Gruppo> Gruppi { get; set; } public DbSet<TariffaOrariaLivello> TariffeOrarieLivello { get; set; }
需求说明
需要获取满足以下条件的TariffaOrariaLivello列表:
- 关联的
Livello.Stato为Attivo(激活状态); - 每个
Livello仅保留DataInizio最新的一条记录; - 结果按
Livello.Progressivo排序; - 每条
TariffaOrariaLivello需预加载对应的Livello及其关联的Gruppo。
当前实现问题
我使用EF6开发,最初编写的代码未能成功加载关联数据,经尝试实现了借助匿名对象中转的可行方案,但该方案不够优雅。现寻求无需通过匿名对象列表的优化解决方案,感谢解答!
解决方案
可以通过两种方式实现无需匿名对象中转的查询,同时满足所有需求:
方式一:先获取最新记录ID集合(性能更优)
先筛选出每个激活状态Livello对应的最新TariffaOrariaLivello的ID,再基于ID查询主数据并预加载关联对象:
var latestTariffaIds = db.Livelli .Where(l => l.Stato == EnumStato.Attivo) .SelectMany(l => l.TariffeOrarie) .GroupBy(t => t.IdLivello) .Select(g => g.OrderByDescending(t => t.DataInizio).First().Id); var result = db.TariffeOrarieLivello .Include(t => t.Livello) .Include(t => t.Livello.Gruppo) .Where(t => latestTariffaIds.Contains(t.Id)) .OrderBy(t => t.Livello.Progressivo) .ToList();
方式二:单查询逻辑紧凑
通过子查询直接判断当前TariffaOrariaLivello是否为对应Livello的最新记录,同时完成筛选、预加载和排序:
var result = db.TariffeOrarieLivello .Include(t => t.Livello) .Include(t => t.Livello.Gruppo) .Where(t => t.Livello.Stato == EnumStato.Attivo && t.DataInizio == db.TariffeOrarieLivello .Where(t2 => t2.IdLivello == t.IdLivello) .Max(t2 => t2.DataInizio)) .OrderBy(t => t.Livello.Progressivo) .ToList();
两种方案均无需依赖匿名对象中转,直接利用EF6的查询语法完成需求。方式一在数据量较大时性能表现更好,方式二则逻辑更简洁。
内容的提问来源于stack exchange,提问作者Liuc
相关产品推荐
相关产品推荐

