Getting past entity framework BeginTransaction - c#

I am trying to make sense of mocking in unit testing and to integrate the unit testing process to my project. So I have been walking thru several tutorials and refactoring my code to support mocking, anyway, I am unable to pass the tests, because the DB method I am trying to test is using a transaction, but when creating a transaction, I get
The underlying provider failed on Open.
Without transaction everything works just fine.
The code I currently have is:
[TestMethod]
public void Test1()
{
var mockSet = GetDbMock();
var mockContext = new Mock<DataContext>();
mockContext.Setup(m => m.Repository).Returns(mockSet.Object);
var service = new MyService(mockContext.Object);
service.SaveRepository(GetRepositoryData().First());
mockSet.Verify(m => m.Remove(It.IsAny<Repository>()), Times.Once());
mockSet.Verify(m => m.Add(It.IsAny<Repository>()), Times.Once());
mockContext.Verify(m => m.SaveChanges(), Times.Once());
}
// gets the DbSet mock with one existing item
private Mock<DbSet<Repository>> GetDbMock()
{
var data = GetRepositoryData();
var mockSet = new Mock<DbSet<Repository>>();
mockSet.As<IQueryable<Repository>>().Setup(m => m.Provider).Returns(data.Provider);
// skipped for brevity
return mockSet;
}
Code under test:
private readonly DataContext _context;
public MyService(DataContext ctx)
{
_context = ctx;
}
public void SaveRepositories(Repository repo)
{
using (_context)
{
// Here the transaction creation fails
using (var transaction = _context.Database.BeginTransaction())
{
DeleteExistingEntries(repo.Id);
AddRepositories(repo);
_context.SaveChanges();
transaction.Commit();
}
}
}
I was trying to mock the transaction part as well:
var mockTransaction = new Mock<DbContextTransaction>();
mockContext.Setup(x => x.Database.BeginTransaction()).Returns(mockTransaction.Object);
but this is not working, failing with:
Invalid setup on a non-virtual (overridable in VB) member: conn =>
conn.Database.BeginTransaction()
Any ideas how to solve this?

As the second error message says, Moq can't mock non-virtual methods or properties, so this approach won't work. I suggest using the Adapter pattern to work around this. The idea is to create an adapter (a wrapper class that implements some interface) that interacts with the DataContext, and to perform all database activity through that interface. Then, you can mock the interface instead.
public interface IDataContext {
DbSet<Repository> Repository { get; }
DbContextTransaction BeginTransaction();
}
public class DataContextAdapter {
private readonly DataContext _dataContext;
public DataContextAdapter(DataContext dataContext) {
_dataContext = dataContext;
}
public DbSet<Repository> Repository { get { return _dataContext.Repository; } }
public DbContextTransaction BeginTransaction() {
return _dataContext.Database.BeginTransaction();
}
}
All of your code that previously used the DataContext directly should now use an IDataContext, which should be a DataContextAdapter when the program is running, but in a test, you can easily mock IDataContext. This should make the mocking way simpler too because you can design IDataContext and DataContextAdapter to hide some of the complexities of the actual DataContext.

I've tried the wrapper/adapter approach, but came up against the problem that when you then go to test the code:
using (var transaction = _myAdaptor.BeginTransaction())
Your mock/fake still needs to return something so the line transaction.Commit();
can still execute.
Normally I'd set the fake of my adapter to return an interface from BeginTransaction() at that point (so I can fake that returned object too), but the DbContextTransaction returned by BeginTransaction() only implements IDisposable so there was no interface that could give me access to the Rollback and Commit methods of DbContextTransaction.
Furthermore, DbContextTransaction has no public constructor, so I couldn't just new up an instance of it to return either (and even if I could, it wouldn't be ideal as I couldn't then check for calls to commit or rollback the transaction).
So, in the end I took a slightly different approach and created a separate class altogether to manage the transaction:
using System;
using System.Data.Entity;
public interface IEfTransactionService
{
IManagedEfTransaction GetManagedEfTransaction();
}
public class EfTransactionService : IEfTransactionService
{
private readonly IFMDContext _context;
public EfTransactionService(IFMDContext context)
{
_context = context;
}
public IManagedEfTransaction GetManagedEfTransaction()
{
return new ManagedEfTransaction(_context);
}
}
public interface IManagedEfTransaction : IDisposable
{
DbContextTransaction BeginEfTransaction();
void CommitEfTransaction();
void RollbackEfTransaction();
}
public class ManagedEfTransaction : IManagedEfTransaction
{
private readonly IDataContext _context;
private DbContextTransaction _transaction;
public ManagedEfTransaction(IDataContext context)
{
_context = context;
}
/// <summary>
/// Not returning the transaction here because we want to avoid any
/// external references to it stopping it from being disposed by
/// the using statement
/// </summary>
public void BeginEfTransaction()
{
_transaction = _context.Database.BeginTransaction();
}
public void CommitEfTransaction()
{
if (_transaction == null) throw new Exception("No transaction");
_transaction.Commit();
_transaction = null;
}
public void RollbackEfTransaction()
{
if (_transaction == null) throw new Exception("No transaction");
_transaction.Rollback();
_transaction = null;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// free managed resources
if (_transaction != null)
{
_transaction.Dispose();
_transaction = null;
}
}
}
}
I then inject that service class into whatever classes need to use a transaction. For example, using the code from the original question:
private readonly DataContext _context;
private readonly IEfTransactionManager _transactionManager;
public MyService(DataContext ctx, IEfTransactionManager transactionManager)
{
_context = ctx;
_transactionManager = transactionManager;
}
public void SaveRepositories(Repository repo)
{
using (_context)
{
// Here the transaction creation fails
using (var managedEfTransaction = _transactionManager.GetManagedEfTransaction())
{
try
{
managedEfTransaction.BeginEfTransaction();
DeleteExistingEntries(repo.Id);
AddRepositories(repo);
_context.SaveChanges();
managedEfTransaction.CommitEfTransaction();
}
catch (Exception)
{
managedEfTransaction.RollbackEfTransaction();
throw;
}
}
}
}

You can find a pretty good solution here.
In short, you need to create proxy class for DbContextTransaction and use it instead of an original one. So that you can mock your proxy and test your method with BeginTransaction().
PS. In article which I linked above, author forgot about the virtual keyword for BeginTransaction() method placed in dbContext class:
// <summary>
/// When we call begin transaction. Our proxy creates new Database.BeginTransaction and gives DbContextTransaction's control to proxy.
/// We do this for unit test.
/// </summary>
/// <returns>Proxy which controls DbContextTransaction(Ef transaction class)</returns>
public virtual IDbContextTransactionProxy BeginTransaction()
{
return new DbContextTransactionProxy(this);
}

Related

How to inject dependencies when those dependencies need a runtime value?

I'm implementing an ASP.NET MVC application and need to implement the Unit Of Work with repositories pattern. My implementation is designed as follows:
The UnitOfWork object is in charge of issuing COMMITs and ROLLBACKs as necessary.
The UnitOfWork object contains a Transaction property, obtaied from the internal DB connection. This object provides atomicity to the operations inside the UnitOfWork.
The UnitOfWork object contains the repositories as properties injected at runtime.
Each repository needs to be provided the IDbTransaction object that UnitOfWork created to support atomicity.
So now I find myself in the strange situation of, in UnitOfWork, having to inject repositories that need a property of UnitOfWork itself in order to be instantiated. So my question is: How do I do this? Or maybe something in the design has to be changed?
I'm using SQL Server at the moment and I use Dapper for the SQL calls. Also, I'm thinking of using Autofac as DI framework.
What I've done so far is to implement UOW and a sample repository. Code as follows.
IRepository.cs:
public interface IRepository<TObj, TKey>
{
Task<TObj> DetallesAsync(TKey id);
Task<TKey> AgregarAsync(TObj obj);
}
DbRepository.cs:
public abstract class DbRepository
{
private readonly IDbConnection _connection;
private readonly IDbTransaction _transaction;
protected IDbConnection Connection
{
get => _connection;
}
protected IDbTransaction Transaction
{
get => _transaction;
}
public DbRepository(IDbTransaction transaction)
{
_transaction = transaction;
_connection = _transaction.Connection;
}
}
RolRepository.cs:
public class MSSQLRolRepository : DbRepository, IRolRepository
{
public MSSQLRolRepository(IDbTransaction transaction)
: base(transaction)
{
}
public async Task<int> AgregarAsync(Rol obj)
{
var result = await Connection.ExecuteScalarAsync<int>(MSSQLQueries.RolAgregar, param: obj, transaction: Transaction);
return result;
}
public async Task<Rol> DetallesAsync(int id)
{
var param = new { Id = id };
var result = await Connection.QuerySingleOrDefaultAsync<Rol>(MSSQLQueries.RolDetalles, param: param, transaction: Transaction);
return result;
}
public async Task<Rol> DetallesPorNombreAsync(string nombre)
{
var param = new { Nombre = nombre };
var result = await Connection.QuerySingleOrDefaultAsync<Rol>(MSSQLQueries.RolDetallesPorNombre, param: param, transaction: Transaction);
return result;
}
public async Task<Rol[]> ListarAsync(int pagina, int itemsPorPagina)
{
var param = new { Pagina = pagina, ItemsPorPagina = itemsPorPagina };
var result = await Connection.QueryAsync<Rol>(MSSQLQueries.RolListar, param: param, transaction: Transaction);
return result.ToArray();
}
public async Task<Rol[]> ListarTodosAsync()
{
var result = await Connection.QueryAsync<Rol>(MSSQLQueries.RolListar, transaction: Transaction);
return result.ToArray();
}
}
IUnitOfWork.cs:
public interface IUnitOfWork : IDisposable
{
IDbTransaction Transaction { get; }
IDenunciaRepository DenunciaRepository { get; }
IUsuarioRepository UsuarioRepository { get; }
IRolRepository RolRepository { get; }
void Commit();
void Rollback();
}
MSSQLUnitOfWork.cs:
public class MSSQLUnitOfWork : IUnitOfWork
{
private bool _already_disposed = false;
private IDbConnection _connection;
private IDbTransaction _transaction;
private IDenunciaRepository _denuncia_repository;
private IUsuarioRepository _usuario_repository;
private IRolRepository _rol_repository;
public IDbTransaction Transaction
{
get => _transaction;
}
public IDenunciaRepository DenunciaRepository
{
get => _denuncia_repository;
}
public IUsuarioRepository UsuarioRepository
{
get => _usuario_repository;
}
public IRolRepository RolRepository
{
get => _rol_repository;
}
public MSSQLUnitOfWork()
{
var connection_string = ConfigurationManager.ConnectionStrings["MSSQL"].ConnectionString;
_connection = new SqlConnection(connection_string);
_connection.Open();
_transaction = _connection.BeginTransaction();
//TODO: Crear repos con transacción
}
public void Commit()
{
_transaction.Commit();
}
public void Rollback()
{
_transaction.Rollback();
}
protected virtual void Dispose(bool disposeManagedObjects)
{
if (!_already_disposed)
{
if (disposeManagedObjects)
{
_transaction?.Dispose();
_connection?.Dispose();
}
_already_disposed = true;
}
}
public void Dispose()
{
Dispose(true);
}
}
I recommend you 3 different things.
Start, Commit and Rollback your data transactions within the repository where you are instantiatign the UnitOfWork - the least I recommend
Create a Service class where you can create an instance of UnitOfWork and pass it the instance or DBContext to the Repositories that you involve in the transactions
Create Repository instance within the UnitOfWork class tha knows the current DBContext then you can access from UnitOfWork the repository operations and starts and ends the transactions in the same context. More recommended
Something like:
UnitOfWorkInstance.MyRepositoryA.AddAsync(...);
UnitOfWorkInstance.MyRepositoryB.AddAsync(...);
UnitOfWorkInstance.Commit();
I find myself in the strange situation of, in UnitOfWork, having to inject repositories that need a property of UnitOfWork itself in order to be instantiated.
It looks like you have a circular dependency and circular dependency is always a bad design and you should break it. If you followed Single Responsibility Principle it should not happens. If it happens the service may have too many responsibilities and you should break it in multiple services or sometime it is because you have too small service and these services should be reunited.
In your case it looks like IUnitOfWork has too many responsibility. What's the goal of this service? what are its responsibilities?
For me, this service should not have any repositories, this service doesn't need any. If any other service needs such a repository, they just have to add a dependency on it. Also the repository don't need to have a dependency on IUnitOfWork but only on IDbTransaction. Furthermore IDbTransaction and IDbConnection should be configured in your dependency injector. If these service need to be instanciated by IUnitOfWork for any reason you can do something like
builder.RegisterType<MSSQLUnitOfWork>()
.As<IUnitOfWork>()
.InstancePerLifetimeScope()
builder.Register(c => c.Resolve<IUnitOfWork>().Transation)
.As<IDbTransaction>();
builder.Register(c => c.Resolve<IUnitOfWork>().Connection)
.As<IDbConnection>();

ninject create NHibernate UnitOfWork only one time, every subsequent instantiation return previous UoW with closed session

iam using ninject.web in my aspx page in this way
my problem is with Nhibernate session management.
this is my ninject module:
public override void Load()
{
Bind<IUnitOfWork>().To<UnitOfWork>();
Bind<IAttivitaRepository>().To<AttivitaRepository>();
}
the page_load and quite every button in a single page create and dispose a unit of work at this way:
using (iuow)
{
iuow.DoSomething();
iuow.SaveAll();
}
in pageLoad works, but every other attempt in the page to use iuow with a new Using block, return that session is closed
this is my UoW impl:
public UnitOfWork()
{
_nhHelper = new SessionFactory();
InizializzaSessione();
_transaction = _session.BeginTransaction();
}
private void InizializzaSessione()
{
if (_session == null)
{
_session = _nhHelper.OpenSession();
}
Area = new AreaRepository(this._session);
Attivita = new AttivitaRepository(this._session);
Societa = new SocietaRepository(this._session);
Persona = new PersonaRepository(this._session);
}
/// <summary>
/// Salva le modifiche sulla base dati
/// </summary>
public void SaveAll()
{
if (_transaction != null)
{
_transaction.Commit();
_transaction = null;
}
}
it seems to me that iuow is resolved (whith a call to New) only at page load, so every new attempt to create Uow return last used one with session disposed.
before attimpting to use ninject what i do is simply:
using (Iuow = new UnitOfWork())
{
....
}
and all works fine
p.s.
i have to remove InRequestScope from binding since it prevent even the page load to work
replace
using (iuow)
{
...
}
by
using (IResolutionRoot.Get<IUnitOfWork>())
{
...
}
Whereas you can inject IResolutionRoot into your classes. No extra bindings necessary (it's a Ninject type).
Caveat: this is service locator.
Alternatively you can hide the IResolutionRoot.Get<IUnitOfWork>() behind an IUnitOfWorkFactory which you can either implement manually or use Ninject.Extensions.Factory to do it for you.
Example
using Ninject;
using Ninject.Syntax;
namespace NinjectTest.SO38013150
{
public interface IUnitOfWork { }
internal class UnitOfWork : IUnitOfWork { }
public interface IUnitOfWorkFactory
{
IUnitOfWork Create();
}
internal class UnitOfWorkFactory : IUnitOfWorkFactory
{
private readonly IResolutionRoot resolutionRoot;
public UnitOfWorkFactory(IResolutionRoot resolutionRoot)
{
this.resolutionRoot = resolutionRoot;
}
public IUnitOfWork Create()
{
return this.resolutionRoot.Get<IUnitOfWork>();
}
}
}
with a test showing that it works (this uses xunit for testing and FluentAssertions for assertions.. they are nuget packages):
using FluentAssertions;
using Ninject;
using Xunit;
namespace NinjectTest.SO38013150
{
public class Test
{
[Fact]
public void Foo()
{
var kernel = new StandardKernel();
kernel.Bind<IUnitOfWork>().To<UnitOfWork>();
kernel.Bind<IUnitOfWorkFactory>().To<UnitOfWorkFactory>();
var factory = kernel.Get<IUnitOfWorkFactory>();
var unitOfWork1 = factory.Create();
var unitOfWork2 = factory.Create();
unitOfWork1.Should().NotBeSameAs(unitOfWork2);
}
}
}
The code is also available as part of my examples collection, here

EF7 DbContext disposal

I am building a desktopp app which uses WPF and EF7 with SqLite. In my service classes I have an instance of IContextScopeLocator injected, which main job is to create and reuse instances of EF DbContexts.
ContextScope
public class ContextScope : IDisposable
{
private readonly PrzylepaDbContext _context;
public ContextScope(PrzylepaDbContext context)
{
_context = context;
}
public EventHandler OnDisposed { get; set; }
public PrzylepaDbContext Context
{
get { return _context; }
}
public void Dispose()
{
OnDisposed.Invoke(this, EventArgs.Empty);
}
}
ContextScopeLocator
public class ContextScopeLocator : IContextScopeLocator
{
private readonly IContextFactory _factory;
public ContextScopeLocator(IContextFactory factory)
{
_factory = factory;
}
private PrzylepaDbContext _currentContext;
private readonly List<ContextScope> _currentScopes = new List<ContextScope>();
public ContextScope GetScope()
{
if (_currentContext == null)
{
//building new EF DbContext if nescesary
_currentContext = _factory.Create();
}
var scope = new ContextScope(_currentContext);
scope.OnDisposed += OnDisposed;
_currentScopes.Add(scope);
return scope;
}
private void OnDisposed(object sender, EventArgs eventArgs)
{
var scope = sender as ContextScope;
Debug.Assert(_currentScopes.Contains(scope));
_currentScopes.Remove(scope);
if (_currentScopes.Count == 0)
{
_currentContext.Dispose();
_currentContext = null;
}
}
}
Then in my service method I can use it like that:
public IEnumerable<Client> GetPublicClients()
{
using (var scope = _scopeLocator.GetScope())
{
return scope.Context.Clients.Where(x => x.IsPublic).IncludeStandard().ToList();
}
}
And even with nested queries I can still get the same context. I will not be calling service methods from multiple threads so I thought this approach would work more less fine for me.
Then in my viewmodel class I receive a message in the following way
private void ClientModifiedMessageHandler(NotifyEntityModifiedMessage<Client> msg)
{
if (msg.EntityId == ModifiedOffer.ClientId)
{
var client = _clientService.GetById(ModifiedOffer.ClientId);
ModifiedOffer.Client = client; //exception
}
}
Exception is raised by the DbContext which was used to get ModifiedOffer from the Db:
"The instance of entity type 'Przylepa.Data.Client' cannot be tracked because another instance of this type with the same key is already being tracked. For new entities consider using an IIdentityGenerator to generate unique key values."
The problem is that the old DbContext is still alive because it subscribes PropertyChanged event in the ModifiedOffer even though Dispose() was called on it (DbContext._disposed is true).
How can I make these DbContexts unsubscribe these events, so that I can do what I want with my model class instances? Thank you

Am I using and disposing Entity Framework's Object Context (per request) correctly?

I have a web application where I have just began to use Entity Framework. I read the beginners tutorials, and topics about benefits of object context per request for web apps.
However, I am not sure my context is at the right place...
I found this very useful post (Entity Framework Object Context per request in ASP.NET?) and used the suggested code :
public static class DbContextManager
{
public static MyEntities Current
{
get
{
var key = "MyDb_" + HttpContext.Current.GetHashCode().ToString("x")
+ Thread.CurrentContext.ContextID.ToString();
var context = HttpContext.Current.Items[key] as MyEntities;
if (context == null)
{
context = new MyEntities();
HttpContext.Current.Items[key] = context;
}
return context;
}
}
}
And in Global.asax :
protected virtual void Application_EndRequest()
{
var key = "MyDb_" + HttpContext.Current.GetHashCode().ToString("x")
+ Thread.CurrentContext.ContextID.ToString();
var context = HttpContext.Current.Items[key] as MyEntities;
if (context != null)
{
context.Dispose();
}
}
Then, I am using it in my pages :
public partial class Login : System.Web.UI.Page
{
private MyEntities context;
private User user;
protected void Page_Load(object sender, EventArgs e)
{
context = DbContextManager.Current;
if (Membership.GetUser() != null)
{
Guid guid = (Guid)Membership.GetUser().ProviderUserKey;
user = context.Users.Single(u => (u.Id == guid));
}
}
protected void _Button_Click(object sender, EventArgs e)
{
Item item = context.Items.Single(i => i.UserId == user.Id);
item.SomeFunctionThatUpdatesProperties();
context.SaveChanges();
}
}
I did read a lot but this is still a little bit confused for me.
Is the context getter okay in Page_Load ? Do I still need to use "using" or will disposal be okay with the Global.asax method ?
If I am confusing something I am sorry and I would be really, really grateful if someone could help me understand where it should be.
Thanks a lot !
Edits following nativehr answer and comments :
Here is the DbContextManager:
public static class DbContextManager
{
public static MyEntities Current
{
get
{
var key = "MyDb_" + typeof(MyEntities).ToString();
var context = HttpContext.Current.Items[key] as MyEntities;
if (context == null)
{
context = new MyEntities();
HttpContext.Current.Items[key] = context;
}
return context;
}
}
}
The page :
public partial class Login : System.Web.UI.Page
{
private User user;
protected void Page_Load(object sender, EventArgs e)
{
if (Membership.GetUser() != null)
{
Guid guid = (Guid)Membership.GetUser().ProviderUserKey;
user = UserService.Get(guid);
}
}
protected void _Button_Click(object sender, EventArgs e)
{
if (user != null)
{
Item item = ItemService.GetByUser(user.Id)
item.SomeFunctionThatUpdatesProperties();
ItemService.Save(item);
}
}
}
And the ItemService class :
public static class ItemService
{
public static Item GetByUser(Guid userId)
{
using (MyEntities context = DbContextManager.Current)
{
return context.Items.Single(i => (i.UserId == userId));
}
}
public static void Save(Item item)
{
using (MyEntities context = DbContextManager.Current)
{
context.SaveChanges();
}
}
}
I would not rely on Thread.CurrentContext property.
Firstly, Microsoft says, Context class is not intended to be used directly from your code:
https://msdn.microsoft.com/en-us/library/system.runtime.remoting.contexts.context%28v=vs.110%29.aspx
Secondly, imagine you want to make an async call to the database.
In this case an additional MyEntities instance will be constructed, and it will not be disposed in Application_EndRequest.
Furthermore, ASP.NET itself does not guarantee not to switch threads while executing a request.
I had a similar question, have a look at this:
is thread switching possible during request processing?
I would use "MyDb_" + typeof(MyEntities).ToString() instead.
Disposing db context in Application_EndRequest is OK, but it produces a bit performance hit, 'cause your context will stay not disposed longer than needed, it is better to close it as soon as possible (you actually don't need an open context to render the page, right?)
Context pre request implementation would make sense if it has to be shared between different parts of your code, insted of creating a new instance each time.
For example, if you utilize the Repository pattern, and several repositories share the same db context while executing a request.
Finally you call SaveChanges and all the changes made by different repositories are committed in a single transaction.
But in your example you are calling the database directly from your page's code, in this case I don't see any reason to not create a context directly with using.
Hope this helps.
Update: a sample with Context per request:
//Unit of works acts like a wrapper around DbContext
//Current unit of work is stored in the HttpContext
//HttpContext.Current calls are kept in one place, insted of calling it many times
public class UnitOfWork : IDisposable
{
private const string _httpContextKey = "_unitOfWork";
private MyContext _dbContext;
public static UnitOfWork Current
{
get { return (UnitOfWork) HttpContext.Current.Items[_httpContextKey]; }
}
public UnitOfWork()
{
HttpContext.Current.Items[_httpContextKey] = this;
}
public MyEntities GetContext()
{
if(_dbContext == null)
_dbContext = new MyEntities();
return _dbContext;
}
public int Commit()
{
return _dbContext != null ? _dbContext.SaveChanges() : null;
}
public void Dispose()
{
if(_dbContext != null)
_dbContext.Dispose();
}
}
//ContextManager allows repositories to get an instance of DbContext
//This implementation grabs the instance from the current UnitOfWork
//If you want to look for it anywhere else you could write another implementation of IContextManager
public class ContextManager : IContextManager
{
public MyEntities GetContext()
{
return UnitOfWork.Current.GetContext();
}
}
//Repository provides CRUD operations with different entities
public class RepositoryBase
{
//Repository asks the ContextManager for the context, does not create it itself
protected readonly IContextManager _contextManager;
public RepositoryBase()
{
_contextManager = new ContextManager(); //You could also use DI/ServiceLocator here
}
}
//UsersRepository incapsulates Db operations related to User
public class UsersRepository : RepositoryBase
{
public User Get(Guid id)
{
return _contextManager.GetContext().Users.Find(id);
}
//Repository just adds/updates/deletes entities, saving changes is not it's business
public void Update(User user)
{
var ctx = _contextManager.GetContext();
ctx.Users.Attach(user);
ctx.Entry(user).State = EntityState.Modified;
}
}
public class ItemsRepository : RepositoryBase
{
public void UpdateSomeProperties(Item item)
{
var ctx = _contextManager.GetContext();
ctx.Items.Attach(item);
var entry = ctx.Entry(item);
item.ModifiedDate = DateTime.Now;
//Updating property1 and property2
entry.Property(i => i.Property1).Modified = true;
entry.Property(i => i.Property2).Modified = true;
entry.Property(i => i.ModifiedDate).Modified = true;
}
}
//Service encapsultes repositories that are necessary for request handling
//Its responsibility is to create and commit the entire UnitOfWork
public class AVeryCoolService
{
private UsersRepository _usersRepository = new UsersRepository();
private ItemsRepository _itemsRepository = new ItemsRepository();
public int UpdateUserAndItem(User user, Item item)
{
using(var unitOfWork = new UnitOfWork()) //Here UnitOfWork.Current will be assigned
{
_usersRepository.Update(user);
_itemsRepository.Update(user); //Item object will be updated with the same DbContext instance!
return unitOfWork.Commit();
//Disposing UnitOfWork: DbContext gets disposed immediately after it is not longer used.
//Both User and Item updates will be saved in ome transaction
}
}
}
//And finally, the Page
public class AVeryCoolPage : System.Web.UI.Page
{
private AVeryCoolService _coolService;
protected void Btn_Click(object sender, EventArgs e)
{
var user = .... //somehow get User and Item objects, for example from control's values
var item = ....
_coolService.UpdateUserAndItem(user, item);
}
}
I think you should read a bit more about repository pattern for EntityFramework and UnitofWork pattern.
Implementing the Repository and Unit of Work Patterns in an ASP.NET MVC
I know this is mvc and you are problably using web forms but you can get an idea of how to implement it.
Disposing the context on each request is a bit strange, because there might be requests where you will not touch the database, so you will be doing unnecessary code.
What you should do is get a layer for data access and implement a repository pattern that you will access on whatever method you will need on the code behind of your page.

Entity Framework 6, Repository pattern and Unit of Work [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I am learning Entity Framework and some design patterns such repository pattern and unit of work. I wrote a program that uses these patterns. In this class I have one DbContext object and I always use this static DbContext. Throughout my application's lifetime, there is only one DbContext object. Am I doing right using this way, think if there are lots of users. Will be any problem about database connections.
UI code:
UnitOfWork uow = GetUnitOfWork(); //There is only one uow object
uow.EmployeeRepository.Insert(new Employee
{
Name = name,
Surname = surname
});
GetUnitOfWork code:
private static UnitOfWork _uow;
public static UnitOfWork GetUnitOfWork()
{
return _uow ?? (_uow = new UnitOfWork());
}
UnitOfWork code:
public class UnitOfWork : IDisposable
{
private static FollowerEntities _context;
private DbContextTransaction _transaction;
//repositories
private EmployeeRepository _employeeRepository;
public UnitOfWork()
{
_context = new FollowerEntities();
}
public EmployeeRepository EmployeeRepository
{
get { return _employeeRepository ?? (_employeeRepository = new EmployeeRepository(_context)); }
}
public void Save()
{
try
{
_transaction = _context.Database.BeginTransaction();
_context.SaveChanges();
_transaction.Commit();
}
catch
{
_transaction.Rollback();
throw;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (disposing)
{
if (_context != null)
{
_context.Dispose();
_context = null;
}
}
}
}
Employee Repository
public class EmployeeRepository : GenericRepository<Employee>
{
public EmployeeRepository(FollowerEntities entities)
: base(entities)
{
}
}
Generic Repository
public class GenericRepository<T> where T : class
{
private FollowerEntities _entities;
private DbSet<T> table = null;
public GenericRepository()
{
}
public GenericRepository(FollowerEntities entities)
{
this._entities = entities;
table = _entities.Set<T>();
}
public IEnumerable<T> SelectAll()
{
return table.ToList();
}
public T SelvectById(object id)
{
return table.Find(id);
}
public void Insert(T obj)
{
table.Add(obj);
}
public void Update(T obj)
{
table.Attach(obj);
_entities.Entry(obj).State = EntityState.Modified;
}
public void Delete(object id)
{
T existing = table.Find(id);
table.Remove(existing);
}
}
private static UnitOfWork _uow;
public static UnitOfWork GetUnitOfWork()
{
return _uow ?? (_uow = new UnitOfWork());
}
Although technically correct, this won't be as useful as you think. You limit the API to a single instance of the UoW. Considering shared scenarios like ASP.NET, this method won't probably be used as often as you think. I suggest removing it.
public UnitOfWork()
{
_context = new FollowerEntities();
}
This unnecessarily couples the context lifetime to UoW lifetime. Instead, separate them:
public UnitOfWork( FollowerEntities context )
{
_context = context;
}
This way, other means of lifetime management (IoC container possibly) could be used.
_transaction = _context.Database.BeginTransaction();
_context.SaveChanges();
_transaction.Commit();
Are you sure saves should always be wrapped in a transaction? What if another transaction exists on the same connection and you want to reuse it?
And the biggest issue - neither the UoW nor repositories are abstracted (with interfaces). This means that the client is still coupled to the sole implementation. You have just created a wrapped over Entity Framework but you can't benefit from it, for example, you can't switch to another implementation without rewriting it. I don't see any solid point in it, beside just excercising.

Categories