WPF MVVM架构下多设备如何同步UnitOfWork数据库上下文?
问题解决方案
核心原因
Entity Framework的DbContext内部默认维护一级缓存,一旦查询过数据就会将实体缓存起来。你的ViewModel是单例模式,绑定的UnitOfWork和DbContext长期存活,这种情况下上下文不会自动感知数据库中其他客户端新增的数据。
具体解决方案
1. 手动刷新上下文缓存
在需要获取最新数据时,主动清空本地缓存或刷新实体:
清空DbSet本地缓存后重新查询
在UserRepository中添加获取最新数据的方法:
public async Task<List<User>> GetAllFreshAsync() { // 清空上下文缓存中的所有User实体 _context.Users.Local.Clear(); return await _context.Users.ToListAsync(); }
之后在ViewModel中调用这个方法,就能拿到数据库中的最新用户列表。
刷新单个已知实体
如果知道要刷新的用户ID,可单独重载实体数据:
var targetUser = await _unitOfWork.Users.GetByIdAsync(targetUserId); if (targetUser != null) { await _context.Entry(targetUser).ReloadAsync(); }
2. 使用无跟踪查询绕过缓存
如果只是读取数据不需要修改,用无跟踪查询直接从数据库拉取最新数据:
// 在UserRepository中实现 public async Task<List<User>> GetAllNoTrackingAsync() { return await _context.Users.AsNoTracking().ToListAsync(); }
这种方式每次查询都会直接访问数据库,不会使用上下文缓存,适合只读场景。
3. 调整UnitOfWork生命周期(推荐)
当前设计中ViewModel单例导致UnitOfWork和DbContext长期存活,可改为让UnitOfWork按需创建、用完即销毁:
1. 修改依赖注入配置
在Prism的Bootstrapper或模块中,将IUnitOfWork注册为瞬态:
containerRegistry.Register<IUnitOfWork, UnitOfWork>(new TransientLifetimeManager());
2. 通过工厂模式创建UnitOfWork
定义工厂接口和实现:
public interface IUnitOfWorkFactory { IUnitOfWork Create(); } public class UnitOfWorkFactory : IUnitOfWorkFactory { private readonly Func<MyDbContext> _contextFactory; public UnitOfWorkFactory(Func<MyDbContext> contextFactory) { _contextFactory = contextFactory; } public IUnitOfWork Create() { return new UnitOfWork(_contextFactory()); } }
3. ViewModel中使用工厂获取新实例
public class UsersViewModel : BindableBase { private readonly IUnitOfWorkFactory _uowFactory; public UsersViewModel(IUnitOfWorkFactory uowFactory) { _uowFactory = uowFactory; } public async Task LoadLatestUsers() { using(var uow = _uowFactory.Create()) { var latestUsers = await uow.Users.GetAllAsync(); // 更新UI绑定的用户集合 } } }
每次创建新的UnitOfWork都会使用全新的DbContext,自然能获取到数据库最新数据,同时也能避免长期存活的上下文导致的内存泄漏问题。
4. 实时数据推送(即时感知场景)
如果需要第二台电脑立刻感知第一台的新增操作,可引入实时通信机制(比如SignalR):
- 第一台提交数据后,通过SignalR通知服务器
- 服务器向所有在线客户端推送更新通知
- 客户端收到通知后,调用上述刷新方法获取最新数据
注意事项
- 长期存活的
DbContext不仅会有缓存问题,还可能因缓存大量实体引发内存泄漏,桌面应用中尽量避免这种设计。 - 无跟踪查询获取的实体无法直接修改提交,若要修改需重新通过有跟踪查询获取实体,或手动附加到上下文。
内容的提问来源于stack exchange,提问作者Stormhead
相关产品推荐
相关产品推荐

