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>();
Related
NOTE
I'm not asking if I should use the Repository pattern, I care about the How. Injecting persistence-related objects into domain classes is not an option for me: it makes Unit Testing impossible (and no, tests using in-memory databases are NOT Unit Tests, as they cover many different classes without isolation), it couples the domain logic with the ORM and it brakes many important principles I practice, like Persistence Ignorance, Separation of Concerns, and others, whose benefits you're welcome to search online. Using EF Core "correctly" is not nearly as important to me as keeping the business logic isolated from external concerns, which is why I'll settle for a "hacky" usage of EF Core if it means the Repository won't be a leaky abstraction anymore.
Original Question
Let's assume the repository's interface is the following:
public interface IRepository<TEntity>
where TEntity : Entity
{
void Add(TEntity entity);
void Remove(TEntity entity);
Task<TEntity?> FindByIdAsync(Guid id);
}
public abstract class Entity
{
public Entity(Guid id)
{
Id = id;
}
public Guid Id { get; }
}
Most of the EF Core implementations I saw online did something like:
public class EFCoreRepository<TEntity> : IRepository<TEntity>
where TEntity : Entity
{
private readonly DbSet<TEntity> entities;
public EFCoreRepository(DbContext dbContext)
{
entities = dbContext.Set<TEntity>();
}
public void Add(TEntity entity)
{
entities.Add(entity);
}
public void Remove(TEntity entity)
{
entities.Remove(entity);
}
public async Task<TEntity?> FindByIdAsync(Guid id)
{
return await entities.FirstOrDefaultAsync(e => e.Id == id);
}
}
The changes are committed in another class, in an implementation of the Unit of Work pattern.
The problem I have with this implementation is that it violates the definition of a repository as a "collection-like" object. Users of this class would have to know that the data is persisted in an external store and call the Save() method themselves. The following snippet won't work:
var entity = new ConcreteEntity(id: Guid.NewGuid());
repository.Add(entity);
var result = await repository.FindByIdAsync(entity.Id); // Will return null
The changes should obviously not be committed after every call to Add(), because it defeats the purpose of the Unit of Work, so we end up with a weird, not very collection-like interface for the repository.
In my mind, we should be able to treat a repository exactly like we would treat a regular in-memory collection:
var list = new List<ConcreteEntity>();
var entity = new ConcreteEntity(id: Guid.NewGuid());
list.Add(entity);
// No need to save here
var result = list.FirstOrDefault(e => e.Id == entity.Id);
When the transaction scope ends, the changes can be committed to the DB, but apart from the low-level code that deals with the transaction, I don't want the domain logic to care about when the transaction is committed. What we can do to implement the interface in this fashion is to use the DbSet's Local collection in addition to the regular DB query. That would be:
...
public async Task<TEntity?> FindByIdAsync(Guid id)
{
var entity = entities.Local.FirstOrDefault(e => e.Id == id);
return entity ?? await entities.FirstOrDefaultAsync(e => e.Id == id);
}
This works, but this generic implementation would then be derived in concrete repositories with many other methods that query data. All of these queries will have to be implemented with the Local collection in mind, and I haven't found a clean way to enforce concrete repositories not to ignore local changes. So my question really boils down to:
Is my interpretation of the Repository pattern correct? Why is there no mention of this problem in other implementations online? Even Microsoft's implementation (which is a bit outdated, but the idea is the same) in the official documentation website ignores local changes when querying.
Is there a better solution to include local changes in EF Core than manually querying both the DB and the Local collection every time?
UPDATE - My Solution
I ended up implementing the second solution suggested by #Ronald's answer. I made the repository save the changes to the database automatically, and wrapped every request in a database transaction. One thing I changed from the proposed solution is that I called SaveChangesAsync on every read, not write. This is similar to what Hibernate already does (in Java). Here is a simplified implementation:
public abstract class EFCoreRepository<TEntity> : IRepository<TEntity>
where TEntity : Entity
{
private readonly DbSet<TEntity> dbSet;
public EFCoreRepository(DbContext dbContext)
{
dbSet = dbContext.Set<TEntity>();
Entities = new EntitySet<TEntity>(dbContext);
}
protected IQueryable<TEntity> Entities { get; }
public void Add(TEntity entity)
{
dbSet.Add(entity);
}
public async Task<TEntity?> FindByIdAsync(Guid id)
{
return await Entities.SingleOrDefaultAsync(e => e.Id == id);
}
public void Remove(TEntity entity)
{
dbSet.Remove(entity);
}
}
internal class EntitySet<TEntity> : IQueryable<TEntity>
where TEntity : Entity
{
private readonly DbSet<TEntity> dbSet;
public EntitySet(DbContext dbContext)
{
dbSet = dbContext.Set<TEntity>();
Provider = new AutoFlushingQueryProvider<TEntity>(dbContext);
}
public Type ElementType => dbSet.AsQueryable().ElementType;
public Expression Expression => dbSet.AsQueryable().Expression;
public IQueryProvider Provider { get; }
// GetEnumerator() omitted...
}
internal class AutoFlushingQueryProvider<TEntity> : IAsyncQueryProvider
where TEntity : Entity
{
private readonly DbContext dbContext;
private readonly IAsyncQueryProvider internalProvider;
public AutoFlushingQueryProvider(DbContext dbContext)
{
this.dbContext = dbContext;
var dbSet = dbContext.Set<TEntity>().AsQueryable();
internalProvider = (IAsyncQueryProvider)dbSet.Provider;
}
public TResult ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken = default)
{
var internalResultType = typeof(TResult).GenericTypeArguments.First();
// Calls this.ExecuteAsyncCore<internalResultType>(expression, cancellationToken)
object? result = GetType()
.GetMethod(nameof(ExecuteAsyncCore), BindingFlags.NonPublic | BindingFlags.Instance)
?.MakeGenericMethod(internalResultType)
?.Invoke(this, new object[] { expression, cancellationToken });
if (result is not TResult)
throw new Exception(); // This should never happen
return (TResult)result;
}
private async Task<TResult> ExecuteAsyncCore<TResult>(Expression expression, CancellationToken cancellationToken)
{
await dbContext.SaveChangesAsync(cancellationToken);
return await internalProvider.ExecuteAsync<Task<TResult>>(expression, cancellationToken);
}
// Other interface methods omitted...
}
Notice the use of IAsyncQueryProvider, which forced me to use a small Reflection hack. This was required to support the asynchronous LINQ methods that comes with EF Core.
Merging the result sets of the same query run against different datasets doesn't work in general.
It's pretty straight forward if you only have local inserts and only use where and select in your queries because then the merge operation is just append.
It gets increasingly more difficult as you try to support more operators like order by, skip & take, group by and also local updates and deletions.
In particular there's no other way to support group by with local updates and deletions but to merge both data sources first and then applying the group by.
Doing this in your app is going to be unfeasible because it would mean retrieving the whole table, applying local changes and then doing the group by.
Something that might work is to transfer your local changes to the database instead and running the query there.
There are two ways that i can think of to achieve this.
Transforming queries
Transform your queries to include local changes by replacing their from clause
so a query like
select sum(salary) from employees group by division_id
would become
select
sum(salary)
from
(
select
id, name, salary, division_id
from employees
-- remove deleted and updated records
where id not in (1, 2)
-- add inserted records and new versions of updated records
union all values (1, 'John', 200000, 1), (99, 'Jane', 300000, 1)
) _
group by division_id
This should also work for joins if you apply the same transformation to the joined tables.
It would require some pretty involved customization to do this with ef though.
This is an idea on how to implement it at least partially with ef, it won't support joins and unfortunately involves some manual sql generation.
static IQueryable<T> WithLocal<T>(this DbContext db)
where T : Entity
{
var set = db.Set<T>();
var changes = db.ChangeTracker.Entries<T>();
var model = db.Model.FindEntityType(typeof(T));
var deletions = changes
.Where(change => change.State == EntityState.Deleted)
.Select(change => change.Entity.Id);
return set
// Hard part left as an exercise for the reader :)
// Generate this from 'changes' and 'model', you can use parameters for the values
.FromSqlRaw("select 1 as id, 'John' as name, 200000 as salary, 1 as division_id union all select 99 as id, 'Jane' as name, 300000 as salary, 1 as division_id")
.Union(set.Where(entity => !deletions.Contains(entity.Id)));
}
you can then use this like so
var query = db.WithLocal<Employee>()
.GroupBy(employee => employee.DivisionId)
.Select(group => group.Sum(employee => employee.Salary));
Keeping a transaction open
A simpler way is to just do the writes to the database but without committing the transaction,
this way all the queries that you run on the same transaction will see the changes but no one else will,
at the end of the request you can then commit or rollback from outside of your repositories.
With this approach your queries will also see database generated values like computed columns, auto increment ids and trigger generated values.
I have never tried this and can't speak for the performance implications of these approaches but if you need this feature I think there aren't many other ways..
It seems there is a misconception about Repositories and Entities here.
First of all, DDD's Entity and EntityFramework's Entity are sligthly different concepts.
In DDD, an Entity is basically a way of keeping track of the evolution of an business concept instance overtime, whereas in EntityFramwork, an Entity is merely a persitence concern.
The repository pattern, in a DDD point of view, won't manipulate Entities directly, but rather Aggregates. Yeah, cool story bro, but what does it change? Long story short, an aggregate can be seen as a transactionnal boundary that protects strict Domain Invariants, invariants that must complies with trancationnal consistency, opposed to eventual consistency.
A repository, in a DDD perspective, will fecth an instance of an Aggregate, that is an object rooted by DDD's Entity called Aggregate Root, with optionnal Entities and Value Objects within it.
With EF, a Repository will do the heavy lifting, fetching datas from one or more SQL Tables, relying on a Factory to provide a fully instanciated and ready-to-use Aggregate. It will also do the transactionnal work in order to save the Aggregate (and its internals components) in a structured, relationnal Fashion in the DB.
But Aggregates shouldn't know about repository. The core model doesn't mind about any persistence details. Aggregate usage belongs to the "Application Layer" or the "Use Case" layer, not the Domain layer.
Let's wrap it up. Let's say you want to implement DDD repository in an asp.net thin app :
class OrderController
{
private IOrderRepository _orderRepository;
public OrderController(IOrderRepository orderRepository)
{
_orderRepository = orderRepository;
}
public async Task PlaceOrder(Guid orderId)
{
var aggregate = await _orderRepository.FindByIdAsync(orderId);
aggregate.PlaceOrder();
await _orderRepository.Save();
}
}
internal interface IOrderRepository
{
void Add(Order order);
void Remove(Order order);
Task<Order> FindByIdAsync(Guid id);
Task Save();
}
internal class Order
{
public Guid Id { get; }
private IList<Item> items;
public static Order CreateOrder(IList<Item> items)
{
return new Order(items);
}
private Order(IList<Item> items)
{
this.Id = Guid.NewGuid();
this.items = items;
}
public void PlaceOrder()
{
// do stuff with aggregate sttus and items list
}
}
What happens here?
The controller is the "Use Case" layer : it's responsible for fecthing the aggregate (the Aggregate Root from the repo, make the Aggregate do its job then command the repo to save its changes.
It could be more transparent with an unit of work in the controller, that would save the injected DbContext (because the concrete repo will have to access different DbSet: Order and Items)
But you get the idea.
You may also want to keep 1 Data Access per table, but it will be used by the Aggregate-dedicated Repository.
Hope it was clear enough
You can look into this repository implementation approach from the Microsoft powered EShopOnWeb project:
According to the rules of Domain-driven design a repository is dedicated to handle a collection of aggregates. The interface in this sample solution looks like the following:
public interface IAsyncRepository<T> where T : BaseEntity, IAggregateRoot
{
Task<T> GetByIdAsync(int id, CancellationToken cancellationToken = default);
Task<IReadOnlyList<T>> ListAllAsync(CancellationToken cancellationToken = default);
Task<IReadOnlyList<T>> ListAsync(ISpecification<T> spec, CancellationToken cancellationToken = default);
Task<T> AddAsync(T entity, CancellationToken cancellationToken = default);
Task UpdateAsync(T entity, CancellationToken cancellationToken = default);
Task DeleteAsync(T entity, CancellationToken cancellationToken = default);
Task<int> CountAsync(ISpecification<T> spec, CancellationToken cancellationToken = default);
Task<T> FirstAsync(ISpecification<T> spec, CancellationToken cancellationToken = default);
Task<T> FirstOrDefaultAsync(ISpecification<T> spec, CancellationToken cancellationToken = default);
}
The interface itself resides in the domain layer (here in this project called application core).
The concrete implementation repository implementations (here for EFCore) reside in the infrastructure layer.
There is a generic EFCore repository implementation for covering common repository methods:
public class EfRepository<T> : IAsyncRepository<T> where T : BaseEntity, IAggregateRoot
{
protected readonly CatalogContext _dbContext;
public EfRepository(CatalogContext dbContext)
{
_dbContext = dbContext;
}
public virtual async Task<T> GetByIdAsync(int id, CancellationToken cancellationToken = default)
{
var keyValues = new object[] { id };
return await _dbContext.Set<T>().FindAsync(keyValues, cancellationToken);
}
public async Task<T> AddAsync(T entity, CancellationToken cancellationToken = default)
{
await _dbContext.Set<T>().AddAsync(entity);
await _dbContext.SaveChangesAsync(cancellationToken);
return entity;
}
public async Task UpdateAsync(T entity, CancellationToken cancellationToken = default)
{
_dbContext.Entry(entity).State = EntityState.Modified;
await _dbContext.SaveChangesAsync(cancellationToken);
}
public async Task DeleteAsync(T entity, CancellationToken cancellationToken = default)
{
_dbContext.Set<T>().Remove(entity);
await _dbContext.SaveChangesAsync(cancellationToken);
}
}
I just referenced some of the methods here.
And for more specific repository methods that fit the requirements you can implement more specific repository interfaces in the domain layer which are again implemented in the infrastructure layer derived by the generic IAsyncRepository and that specific interface. See here for an example (although the method provided is not the best example I think you can get the idea).
With this approach actual saving to the database is completely handled by the repository implementation and not part of the repository interface.
Transactions on the other should not be in neither the domain layer or the repository implementation. So if you need several aggregate updates to be consistent within the same use case this transaction handling should be handled in the application layer.
This also fits with the rule of Eric Evans from his Book Domain-Driven Design.
Leave transaction control to the client. Although the REPOSITORY will insert into and delete
from the database, it will ordinarily not commit anything. It is tempting to commit after
saving, for example, but the client presumably has the context to correctly initiate and
commit units of work. Transaction management will be simpler if the REPOSITORY keeps its
hands off.
See Chapter Six, Repositories.
I see DbContext as the repository it has all the methods you need. Although some application architectures might exists without a need for entity framework and having there own repository patterns, unit of work (EF uses a changetracker) and query specification language (EF uses expressions). Those frameworks architectures seem to use EF to get a straight forward implementation anyway so why invest time in such an architecture?
The only thing that might be useful is query reuse (which I think is quite overrated) but EF has precompiled queries that might be helpful in that area.
You need to use SaveChanges() in order to be able to get new id.
UnitOfWork.cs
private readonly DbContext dbContext;
public UnitOfWork(DbContext dbContext)
{
this.dbContext = dbContext;
}
public void Commit()
{
dbContext.SaveChanges();
}
.
var entity = new ConcreteEntity(id: Guid.NewGuid());
repository.Add(entity);
Commit();
var result = await repository.FindByIdAsync(entity.Id);
EDITED
Unit Of Work.cs
var users = userRepository.GetAll(); // select
var roles = roleRepository.GetAll(); // select
var entity = new ConcreteEntity(id: Guid.NewGuid());
repository.Add(entity);
var order = new Order()
{
InvoiceNo = "00002",
CustomerID = 1,
Amount = 500.00,
OrderDetails = new OrderDetail()
{
ItemID = 1,
Quantity = 5,
Amount = 500.00
}
};
orderRepository.Add(order);
// can add more insert or update or delete here before commit
Commit();
var result = await repository.FindByIdAsync(entity.Id);
var orderresult = await orderRepository.FindByIdAsync(order.Id);
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.
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').
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.
I've encountered what seems to be a common problem: I am updating values in my database, but EF is using its original in-memory copy of the object and these changed values are not reflected in the displayed data. I understand why this is, but I can't figure out a way around it.
The most common solution seems to be to set MergeOptions.NoTracking to turn off change tracking completely (or use the AsNoTracking() extension method when querying) and force a refresh every time the object is accessed, which is fine for my purposes.
I've got a generic base repository which my other repositories inherit from:
public abstract class RepositoryBase<T> where T : class
{
private readonly IDbSet<T> _dbset;
private readonly IUnitOfWork _unitOfWork;
protected RepositoryBase(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
_dbset = _unitOfWork.Database.Set<T>();
}
public virtual IQueryable<T> All()
{
return _dbset;
}
// Some other IQueryable methods here (Query, GetByProductCode etc)
public virtual T Get(long id)
{
return _dbset.Find(id);
}
}
And a DbContext like this:
public class Db : DbContext
{
private IDbSet<Product> _products;
public IDbSet<Product> Products
{
get { return _products ?? (_products = DbSet<Product>()); }
}
public virtual IDbSet<T> DbSet<T>() where T : class
{
return Set<T>();
}
public virtual void Commit()
{
base.SaveChanges();
}
}
If I change the All() method of my repository thus:
public virtual IQueryable<T> All()
{
return _dbset.AsNoTracking();
}
I get the desired result - an update in the database is reflected when the page displaying the products is refreshed. However, I can't do this in the Get() method, as that extension method only works on an IQueryable.
Ideally I'd like to turn this off at the DbContext level as I will never need change tracking, but there doesn't seem to be an obvious way to do this, and there is pretty much zero documentation on the subject (unless someone can point me to some? Please!).
I tried adding a constructor to the DbContext with these configuration options disabled:
public Db()
{
base.Configuration.ProxyCreationEnabled = false;
base.Configuration.AutoDetectChangesEnabled = false;
}
But I must admit I'm only guessing as to what they really do (I only found them through looking at the source code), and they don't seem to have any effect anyway.
Any help would be greatly appreciated. If more info/code would help, please let me know.
If you want to force context to get fresh data each time you don't want to use Find method. Find method always query internal storage first. Use this instead:
public virtual T Get(long id)
{
return All().SingleOrDefault(e => e.Id == id);
}
But I don't understand what do you need this? What do you mean by:
an update in the database is reflected
when the page displaying the products
is refreshed
Context is unit of work. It should be used as unit of work - in web application or web service it means creating new context instance per request. In winforms / wpf application it means using context per logical block (per presenter etc). Because of that you should need this only in very specific scenarios but you want it globally. Your description seems like you are reusing context among requests which is completely bad solution. There are no performance costs in recreating context for each request.