WPF / EntityFramework Context Lifetime - c#

Issue
We are currently having a problem of architecture on a WPF application. It concerns EntityFramework context management, it’s instantiated once and used during the entire life of the application. So we end up with a cache issue, entities are not updated when they were loaded once. Our entities are obsolete when using the application.
Technical specification
Wpf project
.Net Framework 4 client Profile
MEF (Include in Framework 4.0 System.ComponentModel.Composition)
Design pattern MVVM
Multi users application
Architecture
This is a schema of the current architecture.
Service layer
Manage calls to business rules (business layer)
Save the context (through UnitOfWork) after business rules done
Can be called only by a ViewModel
Business layer
Define business rules
Can be called only by service layer
Repository layer
Execute methods which change context datas (insert, update , delete)
Inherit ReadOnlyRepository
Can be called only by business layer
ReadOnlyRepository layer
Execute method which return datas (select)
Can be called everywhere (ViewModel, Service layer, Business layer)
UnitOfWork
Manage context instanciation
Save context
Context available only for repositories
Code
ViewModel
[Export(typeof(OrderViewModel))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class OrderViewModel : ViewModelBase
{
private readonly IOrderManagementService _orderManagementService;
private readonly IOrderReadOnlyRepository _orderReadOnlyRepository;
[ImportingConstructor]
public OrderViewModel(IOrderManagementService orderManagementService, IOrderReadOnlyRepository orderReadOnlyRepository)
{
_orderManagementService = orderManagementService;
_orderReadOnlyRepository = orderReadOnlyRepository;
}
}
Service layer
public class OrderManagementService : IOrderManagementService
{
private readonly IUnitOfWork _unitOfWork;
private readonly IOrderManagementBusiness _orderManagementBusiness;
[ImportingConstructor]
public OrderManagementService (IUnitOfWork unitOfWork, IOrderManagementBusiness orderManagementBusiness)
{
_unitOfWork= unitOfWork;
_orderManagementBusiness = orderManagementBusiness;
}
}
Business layer
public class OrderManagementBusiness : IOrderManagementBusiness
{
private readonly IOrderReadOnlyRepository _orderReadOnlyRepository;
[ImportingConstructor]
public OrderManagementBusiness (IOrderReadOnlyRepository orderReadOnlyRepository)
{
_orderReadOnlyRepository = orderReadOnlyRepository;
}
}
ReadOnlyRepository layer
public class OrderReadOnlyRepository : ReadOnlyRepositoryBase<DataModelContainer, Order>, IOrderReadOnlyRepository
{
[ImportingConstructor]
public OrderReadOnlyRepository (IUnitOfWork uow) : base(uow)
{
}
}
ReadOnlyRepositoryBase
public abstract class ReadOnlyRepositoryBase<TContext, TEntity> : IReadOnlyRepository<TEntity>
where TEntity : class, IEntity
where TContext : DbContext
{
protected readonly TContext _context;
protected ReadOnlyRepositoryBase(IUnitOfWork uow)
{
_context = uow.Context;
}
protected DbSet<TEntity> DbSet
{
get { return _context.Set<TEntity>();
}
public virtual IEnumerable<TEntity> GetAll(System.Linq.Expressions.Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "")
{
IQueryable<TEntity> query = DbSet.AsNoTracking();
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
return query.ToList();
}
public virtual IQueryable<TEntity> All()
{
return DbSet.AsNoTracking();
}
public virtual IQueryable<TEntity> AllWhere(Expression<Func<TEntity, bool>> predicate)
{
return DbSet.Where(predicate).AsNoTracking();
}
public virtual TEntity Get(Expression<Func<TEntity, bool>> predicate)
{
return DbSet.Where(predicate).AsNoTracking().FirstOrDefault();
}
public virtual TEntity GetById(int id)
{
TEntity find = DbSet.Find(id);
_context.Entry(find).State = System.Data.EntityState.Detached;
return DbSet.Find(id);
}
We can see that the context is given to the repository in the constructor. Select methods use the "AsNoTracking ()" method to not cache entities. It's a temporary solution which is obviously not viable in long term.
UnitOfWork
public class UnitOfWork : IUnitOfWork
{
private DataModelContainer _context;
public UnitOfWork()
: this(new DataModelContainer())
{
}
public UnitOfWork(DataModelContainer context)
{
_context = context;
}
public DataModelContainer Context
{
get { return _context; }
}
public int Save()
{
return _context.SaveChanges();
}
}
During the first composition of a service with MEF, UnitOfWork will be instantiated with the default constructor which instantiate the context.
Remarks
Some pieces of code have been omitted for readability.
Goal to achieve
The lifetime of the context is clearly an issue. Knowing that all calls within the same service method must share the same context.
How can we consider modifying the architecture to avoid having a single context ?
Feel free to ask questions ! If needed, I can attach a test project which highlight the issue.

In your application there is only single unit of work but that is not the purpose of a unit a work. Instead, you need to create a unit of work each time "you work with the database". In your case the UnitOfWork should not be part of the MEF container but you can create a UnitOfWorkFactory and inject it from the container. Then the services can create a UnitOfWork each time "work has to be done" with the database:
using (var unitOfWork = unitOfWorkFactory.Create()) {
// Do work ...
unitOfWork.Save();
}
I have modified UnitOfWork so it implements IDisposable. This will allow you to dispose the EF context and also perhaps rollback a transaction if Save was not called. If you have no need for the extra transaction handling you can even get rid of the UnitOfWork class because it simply wraps the EF context and instead you can used the EF context as a unit of work directly.
This change will force you to modify how the service and the repositories are structured but you really have to because your issue is that you have a single unit of work that exists for the entire duration of the application.

Outline clearly distinguished use cases, which would maintain own lifetime scope. This could help preventing other resources leaks as well (which are pretty frequent when using WPF).
Consider generic algorithm:
Initialize lifetime scope.
Using scope:
Allocate views and other WPF resources, allocate business layer, data access (UoW, context, repo).
Load data from db and display it to user.
Wait for user action (1).
Make some changes or load even more data from DB.
Update data representation for user.
Go to (1) until scenario is complete.
Dispose scope, de-allocate resources.
The problem is that your scope currently is your application.
Now imagine that you manage scope at view level. You allocate, display view, get user's input, save changes and then the whole object tree is disposed at once.
Obviously, you should be flexible with scopes. Sometimes it can be useful to use it at view level (like "Edit item"), sometimes it could spread across several views (like wizard, for example). You can even maintain data-driven scopes (imagine you open a project in Visual Studio; begin lifetime scope to manage all resources, which should be available while project 'lives').

Related

EF6, Unit of Work and Repository Pattern - Is this the wrong pattern for a sync service?

I'm writing a sync service between our Salesforce environment and our local environment. My use of the Salesforce API is purely on a batch level due to limitations on # of API requests per day, although I do have details on failures at the atomic level. However, I would like to save changes on a atomic level in my local environment as I don't want an entire transaction to fail if one entity fails.
I am using Entity Framework 6 with a Unit of Work and Repository pattern. Here is my relevant code (Implementation Details Below):
IUnitOfWork
public interface IUnitOfWork: IDisposable
{
IReadUpdateRepository<EntityType1> EntityType1Repository { get; }
ISyncRepository<EntityType2> EntityType2Repository { get; }
ISyncRepository<EntityType3> EntityType3Repository { get; }
...other repos
void SaveChanges();
}
Implementation of IUnitOfWork
public class UnitOfWork : IUnitOfWork
{
private bool _isDisposed;
private DbContext _context;
private ISyncRepository<Entity> _entityRepo;
...other private repos
public UnitOfWork(DbContext context)
{
_context = context;
}
public ISyncRepository<Entity> EntityRepository
{
get
{
if (_entityRepo == null)
_entityRepo = new GenericSyncRepository<Entity>(_context);
return _entityRepo ;
}
}
...other getters for other repos
public void SaveChanges()
{
//client classes handle all errors here
_context.SaveChanges();
}
private void dispose(bool isDisposing)
{
if (!_isDisposed)
{
if (isDisposing)
_context.Dispose();
}
_isDisposed = true;
}
public void Dispose()
{
dispose(true);
}
}
ISyncRepository
public interface ISyncRepository<T> where T : BaseEntity
{
void DeleteItems(IEnumerable<T> items);
void DeleteItemsById(IEnumerable<int> ids);
void DeleteItem(T item);
void InsertItems(IEnumerable<T> items);
void Insert(T item);
T GetItemById(int id);
List<T> GetItems(Expression<Func<T, bool>> predicate = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, string includeProperties = "");
}
Implementation of ISyncRepository
public class GenericSyncRepository<T> : ISyncRepository<T> where T : BaseEntity
{
private readonly DbContext _context;
private readonly DbSet<T> _set;
public GenericSyncRepository(DbContext context)
{
_context = context;
_set = _context.Set<T>();
}
public T GetItemById(int id)
{
var result = _set.Find(id);
return result;
}
public List<T> GetItems(Expression<Func<T, bool>> predicate = null, Func<IQueryable<T>,IOrderedQueryable<T>> orderBy = null ,string includeProperties = "")
{
IQueryable<T> query = _set.AsExpandable();
if (predicate != null)
{
query = query.Where(predicate);
}
if (!String.IsNullOrEmpty(includeProperties))
{
var splitProps = includeProperties.Split(',');
foreach (var prop in splitProps)
{
query = query.Include(prop);
}
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
return query.ToList();
}
public void DeleteItemsById(IEnumerable<int> ids)
{
var items = ids.Select(i => _set.Find(i));
DeleteItems(items);
}
public void DeleteItem(T item)
{
_set.Remove(item);
}
public void DeleteItems(IEnumerable<T> items)
{
_context.Set<T>().RemoveRange(items);
}
public void Insert(T item)
{
_set.Add(item);
}
public void InsertItems(IEnumerable<T> items)
{
_set.AddRange(items);
}
public List<T> GetViewItems(Expression<Func<T, bool>> predicate)
{
IQueryable<T> query = _set.AsExpandable();
return query.Where(predicate).ToList();
}
}
I am using this repository in services that relate to each object group involved in the sync, into which I inject the IUnitOfWork via the constructor:
private readonly IUnitOfWork _uow;
public EntityDataService(IUnitOfWork uow, ICamsSfDTOMapper mapper)
{
_uow = uow;
}
Then use the UoW to fetch repositories to performs queries:
var repo = _unitOfWork.PartyRepository;
var p = repo.GetItems(p => Ids.Contains(someValue));
And when inserts or updates are made, I can call SaveChanges:
_unitOfWork.SaveChanges();
This works great for data retrieval, however for data persistence, I run into a snag. On the local domain side, I want to iterate through objects one by one, saving changes or inserting and calling SaveChanges to persist. If an error occurs, I store it in a result object that I log at the end of each sync step and continue onto the next object to do work on.
However, as my app is currently structured, if a database exception occurs on SaveChanges, that validation error remains in the context until it is disposed. Since this context is injected into each repository in the UoW class, it sticks around for what I presume is the life of the entire sync process.
I am using Autofac for DI in a WindowsService hosted using TopShelf and I'm registering my UoW as such:
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().WithParameter("context", new EntityModel());
Here are my questions:
Should this question be posted to Code Review :)
I feel like I should invert my repository with UoW, with UoW being passed into each repository and my repositories being passed into each service (a service can make use of more than one repository)
Does it make sense to spin up a new DbContext for each SaveChanges and to have one DbContext (the one passed into UoW) as my read context and all other contexts new'ed up when SavingChanges?
Any help would be appreciated.
Doesn't bother me, I only use SO and don't intend to go anywhere else, and don't mind having questions like these on SO.
I would highly recommend that your service as for IRepository and your repository ask for IUoW. I even like to think of IRepository as more than just a barrier to EF. I normally only use a repository if either
I know for a fact in advance I will be implementing a non EF repository as well otherwise
I want to implement some actual logic which I want abstracted from my service and would not make it generic. E.g. I would make a UserProfileRepository, which would have methods such as SyncCurrentUserProfile rather than exposing Add/Insert/Update. Exposing Add/Insert/Update adds nothing to the equation if I don't plan to use a non EF based model.
It depends. If you don't use tracking, and have a lot of unrelated changes over time. Than yes, as each time you add/update something it will add it to the context, which causes future additions/modifications become slower. But if you are adding/modifying 10 things here and there, probably wouldn't worry about it not unless you need a fresh context each time.
I am actually writing a blog post about this. Will try to post a link later.

EF6 Code First with generic repository and Dependency Injection and SoC

After a lots of reading and trying things out with Entity Framework latest stable version (6.1.1).
I'm reading lots of contradictions about whether or not to use repositories with EF6 or EF in general, because it's DbContext already provides a repository and DbSet the UoW, out of the box.
Let me first explain what my solution contains in terms of project and then I'll comeback at the contradiction.
It has a class library project, and an asp.net-mvc project. The class lib project being the data access and where Migrations are enabled for Code First.
In my class lib project I have a generic repository:
public interface IRepository<TEntity> where TEntity : class
{
IEnumerable<TEntity> Get();
TEntity GetByID(object id);
void Insert(TEntity entity);
void Delete(object id);
void Update(TEntity entityToUpdate);
}
And here is the implementation of it:
public class Repository<TEntity> where TEntity : class
{
internal ApplicationDbContext context;
internal DbSet<TEntity> dbSet;
public Repository(ApplicationDbContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
public virtual IEnumerable<TEntity> Get()
{
IQueryable<TEntity> query = dbSet;
return query.ToList();
}
public virtual TEntity GetByID(object id)
{
return dbSet.Find(id);
}
public virtual void Insert(TEntity entity)
{
dbSet.Add(entity);
}
public virtual void Delete(object id)
{
TEntity entityToDelete = dbSet.Find(id);
Delete(entityToDelete);
}
public virtual void Update(TEntity entityToUpdate)
{
dbSet.Attach(entityToUpdate);
context.Entry(entityToUpdate).State = EntityState.Modified;
}
}
And here a few entities:
public DbSet<User> User{ get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<UserOrder> UserOrders { get; set; }
public DbSet<Shipment> Shipments { get; set; }
I don't what to repeat myself but, with EF6 you don't pass repositories anymore, but the DbContext instead. So for DI I've set up the following in the asp-net-mvc project using Ninject:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ApplicationDbContext>().ToSelf().InRequestScope();
}
And this will inject the ApplicationDbContext via constructor injection to upper layer classes where applicable.
Now coming back to the contradiction.
If we don't need a repository anymore because EF already provides that out of the box, how do we do Separation of Concern (abbreviated as SoC in title)?
Now correct me if I'm wrong, but it sounds to me like I just need to do all the data access logic/calculations (like adding, fetching, updating, deleting and some custom logic/calculations here and there (entity specific)) in the asp.net-mvc project, if I don't add a repository.
Any light on this matter is really appreciated.
A little explanation will hopefully clear up your confusion. The repository pattern exists to abstract away database connection and querying logic. ORMs (object-relational mappers, like EF) have been around in one form or another so long that many people have forgotten or never had the immense joy and pleasure of dealing with spaghetti code littered with SQL queries and statements. Time was that if you wanted to query a database, you were actually responsible for crazy things like initiating a connection and actually constructing SQL statements from ether. The point of the repository pattern was to give you a single place to put all this nastiness, away from your beautiful pristine application code.
Fast forward to 2014, Entity Framework and other ORMs are your repository. All the SQL logic is packed neatly away from your prying eyes, and instead you have a nice programmatic API to use in your code. In one respect, that's enough abstraction. The only thing it doesn't cover is the dependency on the ORM itself. If you later decide you want to switch out Entity Framework for something like NHibernate or even a Web API, you've got to do surgery on your application to do so. As a result, adding another layer of abstraction is still a good idea, but just not a repository, or at least let's say a typical repository.
The repository you have is a typical repository. It merely creates proxies for the Entity Framework API methods. You call repo.Add and the repository calles context.Add. It's, frankly, ridiculous, and that's why many, including myself, say don't use repositories with Entity Framework.
So what should you do? Create services, or perhaps it's best said as "service-like classes". When services start being discussed in relation to .NET, all of sudden you're talking about all kinds of things that are completely irrelevant to what we're discussing here. A service-like class is like a service in that it has endpoints that return a particular set of data or perform a very specific function on some set of data. For example, whereas with a typical repository you would find your self doing things like:
articleRepo.Get().Where(m => m.Status == PublishStatus.Published && m.PublishDate <= DateTime.Now).OrderByDescending(o => o.PublishDate)
Your service class would work like:
service.GetPublishedArticles();
See, all the logic for what qualifies as a "published article" is neatly contain in the endpoint method. Also, with a repository, you're still exposing the underlying API. It's easier to switch out with something else because the base datastore is abstracted, but if the API for querying into that datastore changes you're still up a creek.
UPDATE
Set up would be very similar; the difference is mostly in how you use a service versus a repository. Namely, I wouldn't even make it entity dependent. In other words, you'd essentially have a service per context, not per entity.
As always, start with an interface:
public interface IService
{
IEnumerable<Article> GetPublishedArticles();
...
}
Then, your implementation:
public class EntityFrameworkService<TContext> : IService
where TContext : DbContext
{
protected readonly TContext context;
public EntityFrameworkService(TContext context)
{
this.context = context;
}
public IEnumerable<Article> GetPublishedArticles()
{
...
}
}
Then, things start to get a little hairy. In the example method, you could simply reference the DbSet directly, i.e. context.Articles, but that implies knowledge about the DbSet names in the context. It's better to use context.Set<TEntity>(), for more flexibility. Before I jump trains too much though, I want to point out why I named this EntityFrameworkService. In your code, you would only ever reference your IService interface. Then, via your dependency injection container, you can substitute EntityFrameworkService<YourContext> for that. This opens up the ability to create other service providers like maybe WebApiService, etc.
Now, I like to use a single protected method that returns a queryable that all my service methods can utilize. This gets rid of a lot of the cruft like having to initialize a DbSet instance each time via var dbSet = context.Set<YourEntity>();. That would look a little like:
protected virtual IQueryable<TEntity> GetQueryable<TEntity>(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = null,
int? skip = null,
int? take = null)
where TEntity : class
{
includeProperties = includeProperties ?? string.Empty;
IQueryable<TEntity> query = context.Set<TEntity>();
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
query = orderBy(query);
}
if (skip.HasValue)
{
query = query.Skip(skip.Value);
}
if (take.HasValue)
{
query = query.Take(take.Value);
}
return query;
}
Notice that this method is, first, protected. Subclasses can utilize it, but this should definitely not be part of the public API. The whole point of this exercise is to not expose queryables. Second, it's generic. In otherwords, it can handle any type you throw at it as long as there's something in the context for it.
Then, in our little example method, you'd end up doing something like:
public IEnumerable<Article> GetPublishedArticles()
{
return GetQueryable<Article>(
m => m.Status == PublishStatus.Published && m.PublishDate <= DateTime.Now,
m => m.OrderByDescending(o => o.PublishDate)
).ToList();
}
Another neat trick to this approach is the ability to have generic service methods utilizing interfaces. Let's say I wanted to be able to have one method to get a published anything. I could have an interface like:
public interface IPublishable
{
PublishStatus Status { get; set; }
DateTime PublishDate { get; set; }
}
Then, any entities that are publishable would just implement this interface. With that in place, you can now do:
public IEnumerable<TEntity> GetPublished<TEntity>()
where TEntity : IPublishable
{
return GetQueryable<TEntity>(
m => m.Status == PublishStatus.Published && m.PublishDate <= DateTime.Now,
m => m.OrderByDescending(o => o.PublishDate)
).ToList();
}
And then in your application code:
service.GetPublished<Article>();

Repository and UoW pattern with service layer

I'm using Repository and UoW pattern. My services look like this:
public class MyService : IService
{
private readonly IUnitOfWork<MyContext> unitOfWork;
private readonly IMyRepository myRepository;
public MyService(IUnitOfWork<MyContext> unitOfWork, IMyRepository myRepository)
{
this.unitOfWork = unitOfWork;
this.myRepository = myRepository;
}
//Methods...
}
Within services, I need to use other entities (for example to check for rights, etc).
Is it recommended to use the relevant repositories in the service or use the services directly?
Also, for each user we have rights (boolean) for each CRUD action. These rights are stored in the database.
Should checking of rights be done at the controller level or at the service level?
My golden rule is:
When you get business logic in your UI create a service, otherwise use
the repository directly.
So if you have this code in the UI:
var user = repos.Get(1);
user.FirstName = txtFirstName.Text;
repos.Save(user);
You are fine in my opinion. But if you instead have something like:
var user = userRepository.Get(1);
var accessChecker = authorizationRepository.GetForUser(id);
if (!accessChecker.MaySendEmail(user))
throw new SecurityException("You may not send emails");
var emailSender = new EmailSenderService();
emailSender.Send(user, txtDestination.Text, txtMessage.Text);
repos.Save(user);
It's likely that you should use a service instead.
Don't use your UoW to just wrap your database context. Since all your repositories are directly dependent of a given context (more or less, ofc), your repositories can be included in the UoW. Something along the lines of:
public interface IUnitOfWork<TContext> : IDisposable { }
public abstract class UnitOfWork<TContext> : IUnitOfWork<TContext> {
private readonly TContext _context;
protected TContext Context { get{ return _context; } }
protected UnitOfWork(TContext context){
_context = context;
}
}
public interface IMyDbUnitOfWork : IUnitOfWork<MyContext>{
public ICarRepository Cars { get; }
public IOwnerRepository Owners { get; }
}
public class MyDbUnitOfWork : UnitOfWork<MyContext>, IMyDbUnitOfWork{
public MyDbUnitOfWork():base(new MyContext()){}
private ICarRepository _cars;
public ICarRepository Cars {
get{
return _cars ?? (_cars = new CarRepository(Context));
}
}
private ICarRepository _owners;
public IOwnerRepository Owners {
get{
return _owners ?? (_owners = new OwnerRepository(Context));
}
}
}
public class MyService : IService
{
private readonly IMyDbUnitOfWork _unitOfWork;
public MyService(IMyDbUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
//Methods...
}
Obviously you can create this more or less generic, but I believe this should be enough to pass my point.
As a note, and since I normally use IoC frameworks, my services receive an IUnitOfWorkFactory because of the diferent lifestyles.
For the permissions question, it really depends how much control you want to have and how user friendly you want your application to be. Normally is a mix of both. Your application should know if your user has access to the screen but also if you must disable buttons accordingly. Since you also must prevent that, if by any reason, the user can invoke your service method, you can't allow it.
To solve this problem I don't filter by CRUD actions but by Service actions instead, intercepting every service invocation, which makes it easy to map my permissions to the user interface since normally is a 1 to 1 relation between button action and service action.
I think using repositories is just fine. I wouldn't invent a service layer for each of the repos.
Repository is used for abstracting the data access and service layer is to encapsulate business logic, however with recent trend , I find this overkill. Having service layer is fine if they act as controllers but don't try to map one to one to each entity or repo.
I typically use services from the UI and those services in turn use the repositories. I also find it useful to have some domain objects that encapsulate reusable logic in the services.
I do this so that rather than services calling each other and getting circular references, services use a common domain object instead. This avoids circular references and people copying and pasting the same code all over the place.This domain object may then use the repositories if necessary.

ASP.Net MVC & Entity Framework project architecture WITHOUT repository pattern

I'm starting a new small project with ASP.NET MVC and Entity Framework. (SQL Server - around 20 DB tables)
In past projects I’ve used Linq2SQL but it seems to be obsolete.
I've read a lot of posts on using repository pattern for EF (pros and cons) , For me it seems better/simpler to code without repository pattern.
I created the following project architecture :
namespace MySite.Models
{
public class User
{
public Int32 ID { get; set; }
public String Email { get; set; }
public String Password { get; set; }
public String Name { get; set; }
public Int32 Gender { get; set; }
}
}
namespace MySite.DAL
{
public class Users
{
public static IEnumerable<User> GetUsers()
{
using (var context = new DatingSiteContext())
{
return context.Users.ToList();
}
}
public static User GetUserByID(int id)
{
using (var context = new DatingSiteContext())
{
return context.Users.Find(id);
}
}
}
namespace MySite.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
var users = DAL.Users.GetUsers();
return View(users);
}
}
}
What are the disadvantage of using EF like this? (Except lack of unit
testing support)
Is it wrong to create a new DbContext on each call to DAL ? Any Performance hit?
Any other recommended structure for using EF ? Examples? :)
Would you use Linq2SQL in a new project ?
Thank you.
Edit:
The code inside GetUsers() and GetUserByID() is just for example , i understand its a bad practice to return all records from the db (paging or filter in missing)
You actually just created a repository only you call it a 'data access layer' which is, in my opinion, not a good name since Entity Framework is the data access layer. A repository is an abstraction on top of a data access layer, Entity Framework in this case.
Is it wrong to create a new DbContext on each call to DAL ? Any
Performance hit?
Nope, it's just fine, but it might cause trouble when you fetch an entity in one instance of DbContext, and try to update it in another instance.
Would you use Linq2SQL in a new project ?
Nope, Microsoft proposed Entity Framework as the successor of L2SQL and active development of it has stopped.
Any other recommended structure for using EF ? Examples? :)
The approach you use, specific repositories, will result in a lot of redundant code. You could create a generic repository implementing an interface:
public interface IRepository<TEntity>
where TEntity : class, new()
{
IEnumerable<TEntity> GetAll();
TEntity GetById(int id);
IQueryable<TEntity> Table { get; }
}
And an implementation of this:
public EfRepository<TEntity> : IRepository<TEntity>
where TEntity : class, new()
{
private readonly DatingSiteContext _context;
public EfRepository()
{
_context = new DatingSiteContext();
}
private IDbSet<TEntity> Entities
{
get
{
return _context.Set<TEntity>();
}
}
public IEnumerable<TEntity> GetAll()
{
return Entities.ToList();
}
public TEntity GetById(int id)
{
return Entities.Find(id);
}
public IQueryable<TEntity> Table
{
get { return Entities; }
}
}
You can use this repository in your controller like this:
public class HomeController : Controller
{
private readonly IRepository<User> _userRepository;
public HomeController()
{
_userRepository = new EfRepository<User>();
}
public ActionResult Index()
{
var users = _userRepository.GetAll();
var inactiveUsers = _userRepository.Table.Where(u => !u.Active).ToList();
}
}
This generic repository allows you to create mocked repositories:
public class FakeUserRepository : IRepository<User>
{
// ...
}
This approach might seem like a lot of code, but as your entity type amount grows, it will save you a lot of work since all you have to do is create an IRepository<> field in a controller. Yet you have a lot of flexibility with the IQueryable<> property which allows deferred execution.
I'm not saying this is the best method, just one I use regularly in projects. I have to say that I usually write a business (service) layer between the controller and the repositories. I keep my business logic and complex Linq queries (and their execution) there. I also use an IoC container which handles the lifetime of my objects (instances of DbContext and services for example). See this question for more information about that.
My thoughts
Whats the disadvantages:
You cant really unit test anywhere that uses the static methods you have defined in your DAL.
They are also strongly coupled making them more difficult to swap out at runtime, if that became a requirement.
You may start to get additional complications if you need to commit several updates in a transaction
Is it wrong to create a new DbContext on each call?
No, this is fine. The DbContext is lightweight and meant to be used this way.
Other patterns
You already mentioned the repository pattern which is pretty solid, especially when used with a unit of work pattern.
Would you use Linqtosql
No - Linqtosql is pretty much done with, entity framework provides a more complete and generally better solution to this problem
I would rethink how you implemented GetUsers(). You are calling ToList() which will cause all the rows from the underlying table to be returned and stored in memory. If the tables grows large enough you will run into performance issues. It's better to return an IQueryable<User> instead and have your method return context.Users.
Of course you'll run into the problem that the context has already been disposed by the time you execute the IQueryable<>, so you'll need to handle the life cycle of the context in a different way.
If the project is small enough, then you can just store an instance of the Context at the Controller level, and dispose of it when the controller is being disposed. If you do that, make sure you don't do anything in your views that would cause additional queries to be executed (e.g. access a collection off of User if one exists) or else that will error out.

IoC, UnitOfWork with Ninject and Entity Framework

Im trying to implement a generic repository to my service classes.
But when i try to bind my DbConext in Web layer, i need to reference Entity Framework.
My DbContext
public partial class SalesDbContext : DbContext, IUnitOfWork
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
public DbSet<Activity> Activities { get; set; }
/// <summary>
/// Allows saving changes via the IUnitOfWork interface.
/// </summary>
void IUnitOfWork.Commit()
{
base.SaveChanges();
}
My IUnitOfWork
public interface IUnitOfWork
{
/// <summary>
/// Saves changes to all objects that have changed within the unit of work.
/// </summary>
void Commit();
}
My Repository
public class Repository
{
protected IUnitOfWork UnitOfWork { get; set; }
protected SalesDbContext Context
{
get { return (SalesDbContext)this.UnitOfWork; }
}
public Repository(IUnitOfWork unitOfWork)
{
if (unitOfWork == null) throw new ArgumentNullException("unitOfWork");
this.UnitOfWork = unitOfWork;
}
private DbSet<TEntity> GetDbSet<TEntity>() where TEntity : class
{
return this.Context.Set<TEntity>();
}
protected IEnumerable<TEntity> GetAll<TEntity>() where TEntity : class
{
return this.GetDbSet<TEntity>()
.AsEnumerable();
}
protected virtual void SetEntityState(object entity, EntityState entityState)
{
this.Context.Entry(entity).State = entityState;
}
}
And last my Ninject config
private static void RegisterServices(IKernel kernel)
{
IUnitOfWork unitOfWork = new SalesDbContext();
kernel.Bind<IUnitOfWork>().ToConstant(unitOfWork);
kernel.Bind<IMarketService>().To<MarketService>();
}
The problem is that Ninject wants the references to Entity Framework, but i dont want to add it here, it belongs to the data layer.
And do you think the ToConstant implementation for DbContext will cause problem?
If you do not want to reference the EntityFramework from the top level (e.g. web) project, how would you build your application? The top level project needs to have references to all underlying dependencies, so they could be put inside bin folder, in the case of web app.
And definitely it is not Ninject, who wants that reference. It is because you are using classes, that depends on EntityFramework in that project.
There is no problem to have references from the top layer (through middle) to the bottom layer. It could be (design) problem, if it would be other way round (e.g. to have reference from data layer to System.Web).
UPDATE
As OP stated in his comment. There is one possible solution to avoid referencing dependencies of the bottom layer (like EF) from the top layer using the ninject.extensions.xml. It will work only if the intention was to make ninject configuration in the top layer project, but the project itself is not referencing (using) any of the bottom layer classes with dependencies. Also the EF have to be in GAC.
It is not a good conception to bind your DbContext ToConstant() as long as it implements IDisposable. DbContext should be bound in the shortest possible Scope meaningful for the application (e.g. InRequestScope() for web app). Ninject will dispose it at the end of the Scope.
If you let DbContext bound ToConstant, it will hold one connection to database per whole application lifecycle. You can get into trouble with concurrency issues and the DbContext could become inconsistent, when accessed by multiple threads, because it wont be able to keep up on object synchronization.

Categories