You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Entity Framework 6 如何为实体添加时态历史属性并填充

解决思路与实现方案

首先不建议在Review实体中直接添加History导航属性——EF Core的时态表历史记录是数据库维护的独立系统表,并非常规的实体关联关系,强行添加会让EF误解为自关联映射,反而引发不必要的问题。更合理的做法是通过**DTO(数据传输对象)**分离实体模型与展示模型,或者给实体的History属性标记[NotMapped]后手动填充。

方案一:使用DTO(推荐)

1. 定义承载结果的DTO

创建一个专门用于包含历史记录的DTO,避免污染实体模型:

public class ReviewWithHistory
{
    public int Id { get; set; }
    public string Text { get; set; }
    public string Author { get; set; }
    public IList<Review> History { get; set; } = new List<Review>();
}

2. 查询并组装数据

先分离当前版本与历史版本,再通过ID分组匹配:

// 1. 获取所有当前版本的Review(SQL Server中SysEndTime为最大值的是当前版本)
var currentReviews = _dbContext.Reviews.ToList();

// 2. 获取所有历史版本,过滤掉当前版本
var allHistory = _dbContext.Reviews.TemporalAll()
    .Where(r => EF.Property<DateTime>(r, "SysEndTime") != DateTime.MaxValue)
    .ToList();

// 3. 按ID分组历史记录,提升匹配效率
var historyById = allHistory.GroupBy(h => h.Id)
    .ToDictionary(g => g.Key, g => g.ToList());

// 4. 组装最终结果
var result = currentReviews.Select(r => new ReviewWithHistory
{
    Id = r.Id,
    Text = r.Text,
    Author = r.Author,
    History = historyById.TryGetValue(r.Id, out var history) ? history : new List<Review>()
}).ToList();

方案二:给实体添加非映射的History属性

如果一定要在实体中保留History属性,需用[NotMapped]标记,避免EF尝试映射该属性:

1. 修改实体

public class Review
{
    public int Id { get; set; } 
    public string Text { get; set; } 
    public string Author { get; set; } 
    
    [NotMapped] // 告诉EF不要将此属性映射到数据库
    public IList<Review> History { get; set; } = new List<Review>();
}

2. 查询并填充History

// 获取所有版本,同时标记是否为当前版本
var allVersions = _dbContext.Reviews.TemporalAll()
    .Select(r => new 
    {
        Review = r,
        IsCurrent = EF.Property<DateTime>(r, "SysEndTime") == DateTime.MaxValue
    })
    .ToList();

// 分离当前版本与历史版本
var currentReviews = allVersions.Where(v => v.IsCurrent).Select(v => v.Review).ToList();
var historyReviews = allVersions.Where(v => !v.IsCurrent).Select(v => v.Review).ToList();

// 分组历史记录
var historyDict = historyReviews.GroupBy(h => h.Id)
    .ToDictionary(g => g.Key, g => g.ToList());

// 为每个当前Review填充History
foreach (var review in currentReviews)
{
    if (historyDict.TryGetValue(review.Id, out var history))
    {
        review.History = history;
    }
}

注:不同数据库的时态系统列名称可能不同,比如SQL Server是SysStartTime和SysEndTime,如果使用其他数据库需要对应调整系统列名称。

内容的提问来源于stack exchange,提问作者witkacy1986

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 17:28:08