I have a question about using the Repository Pattern and Unit of Work pattern in a MVC Web Application with Entity Framework Core.
I am currently implementing the update functionality in the controller. Now, at this point I am not sure what the best way is to update the entity. I have watched some videos where they said that an Update method should not be present in a repository like this:
public T Update(T entity)
{
DbSet.Attach(entity);
var entry = Context.Entry(entity);
entry.State = System.Data.EntityState.Modified;
}
So that means that I will have to do it like this in the controller:
public IActionResult Edit(int id, [Bind("NeighbourhoodGroup,Neighbourhood,NeighbourhoodId")] Neighbourhoods neighbourhoods)
{
var neighbourhoodsFound = unitOfWork.Neighbourhoods.Get(id);
neighbourhoodsFound.Neighbourhood = neighbourhoods.Neighbourhood;
neighbourhoodsFound.NeighbourhoodGroup = neighbourhoods.NeighbourhoodGroup;
}
However, that means that I will have to do this in all controllers, even if the object has alot of Properties?
I hope someone can give me some advice on what the best approach would be.
In your repository you can have the update functionality as simple as this:
public void Update(T entity)
{
DbSet.Attach(entity);
ApplicationContext.Entry(entity).State = EntityState.Modified;
}
While in the controller or from wherever you prefer to do your update you can get the entity preferably by id, modify all the properties that you want to modify on entity, call the the Update method from the repository which is going to set its state to modified and finally call the Save or SaveAsync method on the EF context. Your EF context should be exposed in your UnitOfWork.
For more detailed explanation you can see this post, it will be very helpful. EF Repository Pattern
I don't see the problem in having Update method in repository. It's OK. It's more complex to read data from repository based on criteria. here you can check an example from Microsoft.
Controller isn't a good place to describe your business cases: do some business logic then save to repository etc. Consider MediatR as a way to describe particular business case instead of putting it into controller.
Also it's useful to read about clean architecture.
Related
I'm fairly new to DDD but I am trying to cram as much as possible as fast as possible. I followed https://github.com/dotnet-architecture/eShopOnContainers as a guide for how to structure my code with Mediatr and EF Core.
Fortunately for this application, the persistence and domain model are the same. Unfortunately for me, my data layer does not match our domain model as it is a legacy db.
So i am separating the domain from persistence which is well and good. But I am having a hard time understanding where if i do this code block in a command handler(trying to make it simple and clear)...
var aggregate = repo.GetById(1234);
aggregate.AddItemToList(item);
repo.SaveChanges();
How can i cause the underlying database context of the repo to be aware of the changes that were applied. Only thing i can think is to have a repo.Update(aggregate) call, that would then try to apply db calls to update various places of the db.
This seems like a smell to me.
Any insights would be great.
Thank you!
Edit:
Should the repository pattern with a separate Domain and Persistence layer return the presistance layer's model or the domain's?
For example:
I have a aggregate Company. And i have a database table called CompanyLegacy which is modeled in the persistence layer using entity framework core.
Should my repository be CompanyLegacyRepository or CompanyRepository? If CompanyRepository, that would mean i query the CompanyLegacy table, and map it to a Company domain model then return it. This model, would not be change tracked. This is where my issue comes from.
But if I'm supposed to do a CompanyLegacyRepository then it seems like that doesn't adhere to DDD guidelines where all actions to be applied to the aggregateroot.
Should the repository pattern with a separate Domain and Persistence
layer return the persistence layer's model or the domain's?
Repository should return your Domain model. If you are using DTOs (such as CompanyLegacy) in your Infrastructure layer, it is the responsibility of your Repository to map them to your Domain models. Please note that in a Layered Architecture, the Application layer is not supposed to know about the DTOs used in the Infrastructure layer... it's your Domain models which are the heart of your application. See this question which is closely related to yours.
Your Repository should be called CompanyRepository. You can define an interface for this repository like:
public interface ICompanyRepository
{
// Company is your domain model not DTO (i.e. your legacy model)
Company GetById(int id);
void Add(Company);
void Update(Company);
}
Change Tracking
Entity Framework change tracking has it's limitations, this question is an example of one of those Disconnected Scenarios, where we cannot rely on EF Change Tracking (because of DTOs). The implementation of the above repository would be like:
public CompanyRepository: ICompanyRepository
{
Private MyDbContext _context;
public CompanyRepository(MyDbContext myDbContext) { _context = myDbContext; }
public Company GetById(int id)
{
var companyLegacy = _context
.CompanyLegacy
.AsNoTracking()
.Where(c => c.id = id)
.FirstOrDefault();
return MyMapper.ToCompany(companyLegacy);
}
public void Add(Company company)
{
var companyLegacy = MyMapper.ToLegacy(company);
_context.Add(companyLegacy);
_context.SaveChanges();
}
public void Update(Company)
{
var companyLegacy = MyMapper.ToLegacy(company);
_context.Update(companyLegacy);
_context.SaveChanges();
}
}
This tutorial is helpful for more advanced operations and you can find more info about EF Core change tracking here.
this answer is related to EF 4/5/6 (not core) but gives you some idea about using unique identifier to decide if an entity should be Added or Updated.
I am trying (and failing) to understand the purpose of the Generic Repository Pattern in the specific instance where it is wrapped around Entity Framework or EF Core.
what is the benefit of writing this:
public void Update(T obj)
{
DbContext.Set<T>().Attach(obj);
DbContext.Entry(obj).State = EntityState.Modified;
DbContext.SaveChanges();
}
When you get the same and more by simply writing it as
public void Update(Movie obj)
{
DbContext.Set<Movie>().Attach(obj);
DbContext.Entry(obj).State = EntityState.Modified;
DbContext.SaveChanges();
}
or
public void Update(Movie obj)
{
var movie = DbContext.Movies.FirsOrDefault(x => x.MovieId == obj.MovieId);
DbContext.Entry(movie).CurrentValues.SetValues(obj);
DbContext.SaveChanges();
}
I guess my real question is why do we wrap a generic repo around what is basically already a generic repository (with more features and optimisations)?
Without being too presumptuous, I would like to answer my own question based off of the comment thread.
The generic repository pattern is a hold-over from the days before the era of Object-Relational Mappers (ORM's) like Entity Framework, xHibernate, Dapper, PetaPoco and a million others.
With the advent of the ORM, all the features found in the Repository Pattern are encapsulated within the ORM itself.
For instance, Entity Framework by default uses a Transaction/UnitOfWork each time you call .SaveChanges() on the DbContext.
It also automatically tracks changes made to entities returned by a query unless you explicitly tell it not to with UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking).
As far as Generic Repositories are concerned, what do you think the following code is:
MyDbContext.Set<WeatherForecast>().Add(forecast);
When I try to insert a entity into the database that has a association with another entity which is already in the database and has an id the entityframework the associated entity gets inserted too. This causes a duplicate entry for the associated entity.
Insert method in the Repository class
public T Insert(T entity)
{
DbSet.Add(entity);
Context.SaveChanges();
return entity;
}
Call of the insert method
this happens somewhere in my Code. I save it into my session variable.
using(var repository = new Repository<User>())
{
user = repository.GetById(id);
}
Then some other place:
Post post = new Post{ User = user, Content ="oO" };
using (var rep = new Repository<Post>())
{
rep.Insert(post);
}
I resolved the duplicate insert with this snippet below. This there a better way than to cast for every entitytype and reattach the assocated entites?
if (entity is Post)
{
Post post = (Post)(object)entity;
Context.Users.Attach(post.User);
}
Most probably your repositories create a new instance of the context instead of sharing one. That's why the newly created context in the Post repository doesn't "see" the user object instance.
Fix this properly by controlling the lifetime of your context and injecting the same instance into different repositories in the same unit of work.
Edit: Container based injection could help you a lot but start by having the data context as the required constructor parameter of your repositories. Then, think of the lifetime of your context.
In a web application a request lifetime is usually most convenient. In a WPF application you could possibly have a view model lifetime, a new context in each view model.
And whether or not the dependency will be satisfied by a container is another story.
These generic repositories are out. There are numerous reasons not to use them. This is one of them. The repositories suggest that you're obeying the single responsibility principle, but they don't. They contain the "Trojan horse" DbContext, which is a component that spills out far more responsibilities than a generic repository should have. Thus, when a repository saves its "own" entities, any old moment it steps out of line by saving others too.
Make your life much easier by throwing out this useless layer. A DbSet is a repository and a DbContext is a unit of work. (I'm only quoting here). In the EF architecture the UoW contains the repositories and these repositories don't have save responsibilities! The UoW has.
Dropping these generic repositories, you can simply do
using(var db = new MyContext())
{
var user = db.Users.Find(id);
Post post = new Post{ User = user, Content ="oO" };
db.Posts.Add(post); // User is not added because it is known to the context.
db.SaveChanges();
}
This is a dedicated method that saves a post connected to a user. There is no point trying to make some generic method for this, because it is a specific task (or use case). As you already noticed, when trying to generalize such tasks you probably can't do without inspecting objects and introducing ugly and clunky if or switch chains.
I've recently been looking into DDD, repositories and the specification pattern and after reading a hand full of blogs and examples I'm trying to come up with a repository that I'm happy with.
I have been exposing IQueryable on my repositories until recently but after understanding that IQueryable is a leaky abstraction because of it is deferred execution and is effectively crossing the boundry from my data layer I have changed it so that my repositories return IEnumerable instead.
So I might have something like this for example:
public interface IUserRepository
{
IEnumerable<User> All();
void Save(User item);
void Delete(User item);
}
I thought okay that seems good but what if I wanted to filter the data my firstname or email? After reading a blog post I implemented a way of passing ICriteria into the All() method.
public IEnumerable<TEntity> All(ICriteria<TEntity> criteria)
{
return criteria.BuildQueryFrom(Set).ToList();
// Set is a DbSet from EntityFramework
}
And an example criteria class:
public class AccountById : ICriteria<Account>
{
private readonly int _id;
public AccountById(int id)
{
_id = id;
}
IQueryable<Account> ICriteria<Account>.BuildQueryFrom(DbSet<Account> dbSet)
{
return from entity in dbSet
where entity.Id == _id
select entity;
}
}
This works fine and I can build these criteria classes to meet my requirements and pass them into the repos and all works well.
One thing I don't like though is being tied to IQueryable because I have to use an ORM that supports Linq so if I wanted to use SqlCommand in my repository for say performance sake or so I can write cleaner SQL rather than the ORM generated SQL, how would I go about doing that?
I would also like to avoid having to write a new method for each filter like FindById, FindByUsername, FindByEmail etc.
How would I go about creating a repository that allows me to specifiy the criteria I want to select without using IQueryable so it would still work whether I used EF, nHibernate or just plain SqlCommand? I'm stuggling to find an example that uses SqlCommand and the specification pattern.
How did people used to do it before ORMs?
Personally, I don't mind IQueryable being a leaky abstraction, because it allows me to write LINQ queries in my service layer and and therefore have more testable code. As long as objects that implement IQueryable are kept inside the service layer (i.e. don't return them to the presentation layer) I don't see a problem. It maximizes the testability of your application. See for instance my blog post about testable LINQified repositories.
I am in the process is designing a website in ASP.NET MVC and am perhaps a little confused as to the exact nature of a repository.
Following the NerdDinner example, my site should have one repository which serves up the entities as I need them. However, I have also heard that you should have different repositorys that deal with specific sets of related entities....?
In the case of my site, there will be a number of entities (around 15 tables) yet the majority are all related. Is it ok / advisable to have one repository that contains all the methods that I'll need for pulling / updating / deleting etc or should I split them down?
I use a generic repository which is plenty for many entities.
For a more complex one, I simply extend this with what's needed. The best of both worlds really.
In domain driven design, there's a rule that repositories are per aggregate root. You can read more about it here.
The more I read, the more I think that NerdDinner is too often seen as a collection of good practices, while it's absolutely not (see here for a discussion of, particularly, NerdDinner repository). That's why people often blame other MS examples like Oxite (and here:
Developers will flock to it, praise
it, and blindly accept it as gospel
because it comes from Microsoft (it's
already well on its way). Sadly, any
developer which adopts its spirit will
be left with an unmaintainble,
untestable and unreadable mess
).
If you use a generic repository which accepts types then I don't see any reason to use more than one.
we use an interface like this:
public interface IRepository
{
void Save<ENTITY>(ENTITY entity)
where ENTITY : Entity;
void Delete<ENTITY>(ENTITY entity)
where ENTITY : Entity;
ENTITY Load<ENTITY>(int id)
where ENTITY : Entity;
IQueryable<ENTITY> Query<ENTITY>()
where ENTITY : Entity;
IList<ENTITY> GetAll<ENTITY>()
where ENTITY : Entity;
IQueryable<ENTITY> Query<ENTITY>(IDomainQuery<ENTITY> whereQuery)
where ENTITY : Entity;
ENTITY Get<ENTITY>(int id) where ENTITY : Entity;
IList<ENTITY> GetObjectsForIds<ENTITY>(string ids) where ENTITY : Entity;
void Flush();
}
then use in code like this:
var returnedObjects = repository.GetAll<ObjectClass>();
var singleObject = repository.Get<ObjectClass>(id);
I create a repository for each data object.
For example, a simple library database could contain the following repositories:
AuthorRepository
BookRepository
PublisherRepository
I think perhaps the verbiage of what is a repository might be confusing you. To me a repository is the data storage (ie; MS SQL Database) of where your data is being stored into.
Following the Repository Pattern I recommend setting up a single respository for each datastore. Most of my projects I use MS SQL so I create a Repository for that DB (I like using Subsonic for my DAL/ORM and it also implements the Repositry pattern and the ActiveRecord pattern) then I create Factories for each table. This lets me wrap up the Subsonic ActiveREcord classes and gives me abstraction.
Hope thats helpfull, perhaps...
You should not create Repositories per each table. As queen3 said, you should create Repository per aggregate root. Like, if Products can have a Category, Category Repository should be a nested class of Products. Follow the domain logic relationship than domain objects.
Queen3 is right, you can follow that Aggregate Root theory. I basically group my repository not thinking in Entities but how they group logically in the application I'm building.
For example:
CustomersRepository
OrdersRepository
...
In CustomerRepository I would put methods for GetCustomers, GetCustomer, AddCustomer, DeleteCustomer, AddCustomerContact, DeleteCustomerContact.
In OrdersRepository I would put methods for GetOrders, GetOrder, AddOrder, CancelOrder, CloneOrder, AddOrderDetail, DeleteOrderDetail and so on.
I tend to use a repository per related group of entitites. i.e orderrepository might have:
Order, and OrderDetail.
and would have another for, say, Customer, CustomerProfile, etc.
This keeps the repository classes neat.
Davy