I’m currently working on a WPF MVVM application using MVVM Light as the MVVM Framework, Entity Framework as the ORM, and MS Synch Framework as the means of synchronizing a Local Sql Compact DB with an online SQL database. The application is also fairly complex in scope, as it is meant to manage an asset, calculating wear and tear on the use of that asset through its lifetime. Thankfully I’m new to all these technologies so ignorance is bliss 🙂 I’ve found lots of tutorials and information on creating the Unit of Work Patter and Repository pattern. However, I’m using the new DbContext, which I’ve read already uses these two patterns.
My current issue relates to using the new DbContext in Entity Framework. I’ve used DbContext Generator template in VS, and so I have a MyDbModelContainer. I’ve used this directly from my view models, which creates a Context per VM, which I’m pretty sure is a bad idea. Here is my constructor for a Parent/Child type data entry scenario, I construct the container here, and them use MVVM Light to message over a selected item to the child VM.
Private FatigueDbContext As FatigueModelContainer
Public Sub New()
If IsInDesignMode = False Then
FatigueDbContext = New FatigueModelContainer
FatigueDbContext.CtMaterials.Load()
CtMaterialsCollection = FatigueDbContext.CtMaterials.Local
FatigueDbContext.CtManufactures.Load()
CtManufactures = FatigueDbContext.CtManufactures.Local
End If
End Sub
I want to keep the Context open for the lifetime of my View-Model so that I can use MyDbModelContainer.MyTable.Local for bindings. So while this is working, how should I handle this correctly?
My gut feeling is I need to somehow wrap the auto-generated MyDbModelContainer into some classes that basically only contain the tables and functions that I need to work with on that View-Model.
I’m not using a View-Model Locator, but rather another View-Model to manage my views, got the idea from Rachel’s blog , and I like the concept. However, it means that I’m creating all my View-Models up front, and initializing any of the view model dependencies up front. I only have one window, and am just switching between View-Models they stay in memory and I don’t have any way to close my DbContext when switching to a new View-Model.
Here is the code for the Shell View-Model
Public Class ShellViewModel
Inherits ViewModelBase
#Region "Fields"
Private _changePageCommand As ICommand
Private _currentPageViewModel As IPageViewModel
Private _pageViewModels As List(Of IPageViewModel)
#End Region
Public Sub New()
Dim DialogService As New ModalDialogService
' Add available pages
PageViewModels.Add(New ImportJobDataViewModel(DialogService))
PageViewModels.Add(New TestViewModel())
PageViewModels.Add(New ReverseBendUtilityViewModel(DialogService))
' Set starting page
CurrentPageViewModel = PageViewModels(0)
End Sub
#Region "Properties / Commands"
Public ReadOnly Property ChangePageCommand() As ICommand
Get
If _changePageCommand Is Nothing Then
_changePageCommand = New RelayCommand(Of IPageViewModel)(Sub(param) ChangeViewModel(param))
End If
Return _changePageCommand
End Get
End Property
Private Function IsViewPageModel(viewPageModel As IPageViewModel) As Boolean
If TypeOf (viewPageModel) Is IPageViewModel Then
Return True
Else
Return False
End If
End Function
Public ReadOnly Property PageViewModels() As List(Of IPageViewModel)
Get
If _pageViewModels Is Nothing Then
_pageViewModels = New List(Of IPageViewModel)()
End If
Return _pageViewModels
End Get
End Property
Public Property CurrentPageViewModel() As IPageViewModel
Get
Return _currentPageViewModel
End Get
Set(value As IPageViewModel)
If _currentPageViewModel IsNot value Then
_currentPageViewModel = value
RaisePropertyChanged(Function() CurrentPageViewModel)
End If
End Set
End Property
#End Region
#Region "Methods"
Private Sub ChangeViewModel(viewModel As IPageViewModel)
If Not PageViewModels.Contains(viewModel) Then
PageViewModels.Add(viewModel)
End If
CurrentPageViewModel = PageViewModels.FirstOrDefault(Function(vm) vm Is viewModel)
End Sub
#End Region
End Class
So to sum it all up… Should I be creating some separate class aside from the auto-generated FatigueModelContainer, what would that class look like, would it be just one more class, or would it be separate classes based on the business operations. Such as a class to Add, Update and Delete Manufactures, a class to Add, Update and Delete Materials, etc. Where should I be inserting it into the VM? Presumably in the Shell-View-Model?
You can solve this problem without really touching your db context. The idea is that even if the VM stays in memory, you only need the model instance to be initialized when the VM’s view is active.
There is a nice way of going about this in Caliburn.Micro: Screens and Conductors, but it’s really not specific to the mvvm framework.
In the most basic case, as Rachel mentioned in the comment above, you extend your
IPageViewModelto include functions which handle activation- and deactivation-logic for the VM: activation logic is called when the VM is activated, deactivation logic is called when the VM is deactivated.The actual call to activate/deactivate would be made in the container for the
IPageViewModels, for instance:That way you can close the db connection/detach the DbContext when a page is deactivated and open it when the page is activated.