如何在 EF Core 中仅包含相关表的最新记录

Posted

技术标签:

【中文标题】如何在 EF Core 中仅包含相关表的最新记录【英文标题】:How do I include the latest record only of a related table in EF Core 【发布时间】:2020-08-28 02:28:01 【问题描述】:

我正在 .net core 3.1 中构建一个应用程序。我想显示资产列表以及每个资产进行视觉和完整的 pat 测试的最后日期。

我使用的表/模型如下:

  public class Asset
    
        public int AssetID  get; set; 
        public string Title  get; set; 
        public int AssetCatID  get; set; 
        public string Manufacturer  get; set; 
        public bool RequiresPAT  get; set; 

        public AssetCat AssetCat  get; set; 
        public PAT PAT  get; set; 
    


    public class AssetCat
    
        public int AssetCatID  get; set; 
        public string CategoryTitle  get; set; 

        public virtual ICollection<Asset> Assets  get; set; 
    

    public class PAT
    
        public int PATID  get; set; 
        public int AssetID  get; set; 
        public int CheckTypeID  get; set; 
        public DateTime CheckDate  get; set; 
        public string CheckedBy  get; set; 

        public Asset Asset  get; set; 
        public CheckType CheckType  get; set; 
    

我没有在此处包含 CheckType 表,但 CheckTypeID 1 = 完整测试,CheckTypeID 2 = Visal 测试

RequiresPAT 的每个资产对于这两种类型的测试都有多个条目,我需要列出资产以及每种类型的最后一次测试的日期。

  var AssetQuery = _context.Assets
    .Where(a => a.RequiresPAT)
    .Include(a => a.AssetCat)
    .Include(a => a.PAT) // needs to just include latest PAT record where CheckTypeID = 1 if it exists AS FullPAT
    .Include(a => a.PAT) // needs to just include latest PAT record where CheckTypeID = 2 if it exists AS VisualCheck
    .ToListAsync();

我已经看到,在 EF 5 中稍后会在包含上使用 .Where,但目前尚不可用。我尝试在 PAT 记录上使用 .OrderByDecending(p => p.CheckDate).FirstorDefault() 的变体,但我无法弄清楚如何将它们组合在一起。

我想返回一个模型以在索引样式页面上使用,理想情况下显示如下内容:

Model.Asset.AssetID | Model.Asset.AssetTitle | Model.Asset.AssetCat.CategoryTitle | Model.Asset.FullPat.CheckDate | Model.Asset.VisualCheck.CheckDate

我对 .net / ef / c# 很陌生,所以任何指针都将不胜感激。我确切地知道如何在 SQL 中为经典 ASP 编写视图,但试图为 .net 核心制定最佳方法

【问题讨论】:

【参考方案1】:

正如您在 ef-core 问题 issue-1833 here 中看到的,有以下评论

从历史上看,EF 不支持此功能,但是这将是一个不错的功能。我们必须使用 Linq 树重写在我们的代码库中自己实现类似的东西。它希望 EF 团队考虑这一点。

因此,您唯一的解决方案是使用 EF-Core 5,或者执行类似变通解决方案的方法,这在性能方面非常糟糕

var story = await _context.Stories
    .Include(x => x.Paragraphs)
    .Include(x => x.User)
    .Include(x => x.Tips)
    .Include(x => x.Images)
    .Include(x => x.Comments)
    .ThenInclude(x => x.User)
    .SingleOrDefaultAsync(x => x.Id == storyId);
if (story == null)
    return null;

story.Comments = story.Comments.Where(x => !x.IsDeleted).ToList();
story.Images = story.Images.Where(x => !x.IsDeleted).ToList();
story.Paragraphs = story.Paragraphs.Where(x => !x.IsDeleted).ToList();
story.Tips = story.Tips.Where(x => !x.IsDeleted).ToList();
return story;

所以暂时解决它(如果性能不是太忙的话)或使用 EF Core 5 预览版preview announcement

如 cmets 所述,唯一可行的选择:

唯一的解决方法是编写原始 SQL,但在许多情况下,几乎所有查询都需要它,所以这不是一个选项,否则为什么要使用 ORM 开始。

【讨论】:

感谢您的指导,非常有帮助!我已经使用了 EF 5 预览版,现在可以使用 .Include(c =&gt; c.PAT .Where(p =&gt; p.CheckTypeID == 1).OrderByDescending(p =&gt; p.CheckDate).Take(1)) 行,效果很好。关于尝试使用两个不同的过滤器两次包含 PAT(一个 CheckTypeID = 1 和一个 where = 2),是否有一种别名机制,包括我建议的方式你知道吗?

以上是关于如何在 EF Core 中仅包含相关表的最新记录的主要内容,如果未能解决你的问题,请参考以下文章

如何在 EF Core 5 中为自定义 SQL 配置导航属性

EF Core 如何实现对值对象更改的审计日志

如何在 EF7(Core) 中创建与同一个表的多个关系?

如何从 EF 中的表中仅选择某些字段

EF Core开发模式之Code First

如何在 EF Core 中按条件获取最新条目?