在用C#开发员工信息管理系统时遇到问题:
我将一名名为“钱七”的员工姓名修改为“钱八”。在打开该员工的详细信息页面时,确认姓名已成功更新为“钱八”。然而,在主页面的列表中,通过搜索关键词“八”进行检索
时,虽然能够搜到该员工,但列表中显示的姓名仍为“钱七”。此外,刷新列表后,显示的姓名依旧是“钱七”。
问题根源:EF Core的缓存机制
经过分析,问题的根本原因在于EF Core的缓存机制:
- 多个DbContext实例:应用程序中不同窗体创建了各自的DbContext实例
- 一级缓存:每个DbContext实例维护自己的实体缓存
- 缓存不一致:一个DbContext中的修改不会自动同步到其他DbContext
编辑员工信息时 : EmployeeEditForm 使用自己的DbContext实例更新数据库 主窗体显示列表时 : MainForm 使用自己的DbContext实例查询数据 缓存不一致 :两个不同的
DbContext实例导致主窗体可能显示旧的缓存数据,而不是数据库中的最新数据。
解决方案一:强制刷新策略
最初采用的解决方案是通过强制刷新来绕过缓存问题:
public void RefreshEmployeeList()
{// 释放旧DbContext_context?.Dispose();// 创建新DbContext实例,强制从数据库重新加载_context = new AppDbContext();// 重新绑定数据var employees = _context.Employees.ToList();dataGridView.DataSource = employees;
}
优点:
-
实现简单,快速解决问题
-
确保获取数据库最新数据
缺点:
-
性能开销大(频繁创建DbContext)
-
代码冗余(每个窗体都需要实现刷新逻辑)
-
资源浪费(多个DbContext实例)
-
维护困难
解决方案二:单例模式架构
经过优化,我们采用了更优雅的单例模式解决方案:
单例模式核心实现
public class DbContextManager : IDisposable
{private static readonly Lazy<DbContextManager> _instance = new Lazy<DbContextManager>(() => new DbContextManager());private AppDbContext _context;private readonly object _lockObject = new object();public static DbContextManager Instance => _instance.Value;public AppDbContext Context => _context ??= new AppDbContext();private DbContextManager() { }public void RefreshContext(){lock (_lockObject){_context?.Dispose();_context = new AppDbContext();}}public void Dispose(){_context?.Dispose();}
}
在窗体中的使用方式
public class MainForm : Form
{// 所有窗体使用同一个DbContextManager实例private DbContextManager _dbManager = DbContextManager.Instance;private void LoadEmployees(){var employees = _dbManager.Context.Employees.ToList();dataGridView.DataSource = employees;}private void SearchEmployees(string keyword){var results = _dbManager.Context.Employees.Where(e => e.Name.Contains(keyword)).ToList();dataGridView.DataSource = results;}
}
两种方案对比分析
| 特性 | 强制刷新方案 | 单例模式方案 |
|---|---|---|
| 数据一致性 | 通过刷新保证 | 天然保证 |
| 性能表现 | 频繁创建实例,性能差 | 单实例,性能优 |
| 资源使用 | 多个实例,资源浪费 | 单一实例,资源节省 |
| 代码质量 | 冗余重复代码 | 集中管理,代码简洁 |
| 可维护性 | 分散管理,维护困难 | 集中管理,易于扩展 |
| 线程安全 | 需要额外处理 | 内置线程安全机制 |
总结
通过从"强制刷新"到"单例模式"的架构演进,我们不仅解决了数据同步问题,还提升了系统的整体质量。单例模式提供了:
-
根本性解决:从架构层面消除缓存不一致
-
性能提升:减少不必要的资源创建
-
代码优化:统一管理逻辑,提高可维护性
-
扩展基础:为后续功能扩展提供良好基础
学了设计模式就得用嘛,虽然现在都是用ai来写代码,但是作为ai的直接领导指挥它写出更优美的代码是我们的优势所在。