patterncsharpMinor
Enabling discard pending changes on DbContext
Viewed 0 times
discardpendingchangesdbcontextenabling
Problem
This code review request is tightly coupled with this SO question, this is the solution I implemented to solve the problem being asked about there.
All my ViewModels get constructor-injected with a Model that itself gets constructor-injected with a
Obviously since the
Now
The model that needs to control its
And then the ViewModel that needs to discard pending changes can do it like this (given a
```
var model = _model as IDiscardModelChanges;
if (mode
All my ViewModels get constructor-injected with a Model that itself gets constructor-injected with a
DbContext-derived class, and that works well in all cases, except when the View has a command to allow the user to discard pending changes, in which case the DbContext should be disposed and then reinstantiated.Obviously since the
DbContext is created by an IoC container it would be a very bad idea to just dispose and reinstantiate the context, so I came up with a solution involving a factory.public interface IContextFactory where TContext : DbContext
{
TContext Create();
}
public interface IDiscardModelChanges
{
void DiscardChanges();
}Now
IDiscardModelChanges is implemented by the model, so to facilitate this I've created a base class that will ensure I have a context factory at hand:public abstract class DiscardableModelBase : IDiscardModelChanges, IDisposable
where TContext : DbContext
{
private readonly IContextFactory _factory;
protected TContext Context { get; private set; }
protected DiscardableModelBase(IContextFactory factory)
{
_factory = factory;
Context = _factory.Create();
}
public virtual void DiscardChanges()
{
Context.Dispose();
Context = _factory.Create();
}
public void Dispose()
{
Context.Dispose();
}
}The model that needs to control its
DbContext then derives from this class:public class SomeModel : DiscardableModelBase, ISomeModel
{
public SomeModel(IContextFactory factory)
: base(factory)
{ }
/* methods that act upon protected Context property */
}And then the ViewModel that needs to discard pending changes can do it like this (given a
private readonly ISomeModel _model):```
var model = _model as IDiscardModelChanges;
if (mode
Solution
As stated by previous comments, there is no need to throw away the context.
But since this is a code review, and not a concept review I'll leave that part aside.
All your
The changes might seem small, but the impact is big. In your example, you are going to pull in Entity Framework everywhere you are using this application, which isn't needed at all.
You are not doing anything entity framework related, you are doing something with disposable objects. This could be a
PS: I know this post is old. But people should really be aware of the issue with this code.
But since this is a code review, and not a concept review I'll leave that part aside.
All your
TContext generics are to be inheriting from DbContext, but nowhere in any class do you use any of DbContext's properties or methods. You are only using the .Dispose method, which comes from the IDisposable interface. I've refactored your code to have this result:public interface IContextFactory where TContext : IDisposable
{
TContext Create();
}
public interface IDiscardModelChanges
{
void DiscardChanges();
}
public abstract class DiscardableModelBase : IDiscardModelChanges, IDisposable
where TContext : IDisposable
{
private readonly IContextFactory _factory;
protected TContext Context { get; private set; }
protected DiscardableModelBase(IContextFactory factory)
{
_factory = factory;
Context = _factory.Create();
}
public virtual void DiscardChanges()
{
Context.Dispose();
Context = _factory.Create();
}
public void Dispose()
{
Context.Dispose();
}
}The changes might seem small, but the impact is big. In your example, you are going to pull in Entity Framework everywhere you are using this application, which isn't needed at all.
You are not doing anything entity framework related, you are doing something with disposable objects. This could be a
StreamWriter, etc...PS: I know this post is old. But people should really be aware of the issue with this code.
Code Snippets
public interface IContextFactory<out TContext> where TContext : IDisposable
{
TContext Create();
}
public interface IDiscardModelChanges
{
void DiscardChanges();
}
public abstract class DiscardableModelBase<TContext> : IDiscardModelChanges, IDisposable
where TContext : IDisposable
{
private readonly IContextFactory<TContext> _factory;
protected TContext Context { get; private set; }
protected DiscardableModelBase(IContextFactory<TContext> factory)
{
_factory = factory;
Context = _factory.Create();
}
public virtual void DiscardChanges()
{
Context.Dispose();
Context = _factory.Create();
}
public void Dispose()
{
Context.Dispose();
}
}Context
StackExchange Code Review Q#32156, answer score: 5
Revisions (0)
No revisions yet.