C# ViewModel中具有静态DbContext的WPF应用程序
我正在使用MVVM、代码优先和存储库模式开发WPF应用程序。我需要一个后台任务,它处理来自客户端的Web服务器请求,并将新数据保存到数据库中 问题是每个ViewModel都有一个属性(ObservableCollection),该属性获取Repository.GetObservableCollection()。因此,每个ViewModel都有一个存储库实例,该实例具有相同的DbContext(因此,在保存复杂实体时,我不会得到DbException)。此DbContext在每次回购中都会一直存在到应用程序结束,并从MainViewModel注入到VM的构造函数中 当我从后台任务将新数据保存到数据库时,GUI不会更新,因为我在那里使用不同的DbContext(由于并发请求,我不得不): 我尝试了两种方法:C# ViewModel中具有静态DbContext的WPF应用程序,c#,wpf,mvvm,entity-framework-6,dbcontext,C#,Wpf,Mvvm,Entity Framework 6,Dbcontext,我正在使用MVVM、代码优先和存储库模式开发WPF应用程序。我需要一个后台任务,它处理来自客户端的Web服务器请求,并将新数据保存到数据库中 问题是每个ViewModel都有一个属性(ObservableCollection),该属性获取Repository.GetObservableCollection()。因此,每个ViewModel都有一个存储库实例,该实例具有相同的DbContext(因此,在保存复杂实体时,我不会得到DbException)。此DbContext在每次回购中都会一直存在
问题是我如何重构它以允许GUI和后台与实体交互。如何正确组合存储库和MVVM?是否使用绑定机制?您可以在更改集合后更新它(假设您的VM实现了
INotifyPropertyChanged
接口)。不要将ViewModel实体直接链接到DBDataContext
。
您需要在ViewModel中定义一个ObservableCollection
,并在XAML中定义其绑定
之后,您将通过从持久层调用函数来异步更新集合。因此,您最好使用一个LoadAsync
,或者您可以将数据库检索包装到一个任务中。这种方法将起作用,因为await
将捕获UI线程的SynchronizationContext
,并将更新UI线程中的组件
实际的DataContext
必须隐藏在该持久层中,并且必须对ViewModel保持未知
对评论的答复
如果我不将DbContext传递给ViewModels(ViewModels又将其传递给
它的存储库),如何获取存储库的上下文,以便
召唤
point void LoadAll(){
context.Set().Load();
}
及
公共ObservableCollection GetObservableCollection(){
返回context.Set().Local;
}
根据我的回答,ViewModel可以调用持久层函数来加载集合(甚至不需要持久层返回的类型是可观察的)。
关键是,您不会返回void
,您可能会使用LoadAsync
,以便在将返回的数据分配给ViewModel属性的基础集合时,可以等待它
因此,我必须使用Dispatcher.Invoke
与repos/viewmodels交互
否,不要使用Dispatcher.Invoke
与存储库数据库上下文交互。使与DB的交互异步。请注意,Dispatcher.Invoke
仅用于UI层。是的,我是这样做的。这对我有用。我的问题在于我有两个DbContext实例——第一个在ViewModel.Repository中,第二个DbContext是在请求到来时根据需要创建的。如何从第二个DbContext影响(添加)第一个DbContext(=保持它们同步)?我是说,它是本地的财产。我不能只在构造函数中传递第一个DbContext,因为同一上下文上的并发请求会导致异常。Invoke在UI中引入了一个小的延迟。我只需要统一这些上下文,或者类似的东西。那么,你能使用上下文的全局版本吗?处理web请求并将新数据插入数据库的代码部分可能不能使用相同的全局上下文,因为当两个请求同时处理时,然后,相同上下文上的这些操作会导致并发异常。这可能很有用。好的,但是如果我不将DbContext传递给ViewModels(ViewModels又将其传递给它的存储库),那么如何将上下文传递给存储库,这样我就可以调用public void LoadAll(){context.Set().Load();}
和public observeCollection getobserveCollection(){return context.Set().Local;}
我已经在使用ObservableCollection
并将其绑定。此外,后台数据插入在不同的线程中运行,因此我必须使用Dispatcher.Invoke与repos/viewmodels交互。答案已更新,如果您仍有疑问,请为我创建解决方案,即使用Messenger/Dispatcher模式在viewmodels之间传递消息。
using (var db = new DbContextManager())
{
var client = new Client();
db.Client.Add(client);
db.SaveChanges();
}
point void LoadAll() {
context.Set<T>().Load();
}
public ObservableCollection<T> GetObservableCollection() {
return context.Set<T>().Local;
}