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
相关产品推荐
相关产品推荐

