I'm still on my eternal quest to build (and understand) modern programming convention of decoupling, IoC, DI, etc. I'm to the part where I am trying to figure out how to build a repository. I've examined the post at Database abstraction layer design - Using IRepository the right way? which was very helpful, but I've still got some problems that are just befuddling me all the way.
I have my program in now 4 layers...
Web (Project | ASP.NET MVC Application) - References Models.dll and Persistence.dll
Models (Domain Objects)
Persistence (Fluent nHibernate Mapping of Domain Objects)
Utilities (Providers, Repositories)
Now then, I'm trying to write up a simple Membership Repository. My first task... ?
Check to see if an email address exists when someone tries to register. That seemed all well and good - so I go to try and figure out where to place this.
At first though, I would just place it inside of the MembershipProvider
class CreateUser
method. This, however, resides in the Utilities project. So far, Utilities has no knowledge of nHibernate. Only the Persistence Project has any knowledge of nHibernate.
So then, my CreateUser
method needs to query my database. So what's the best practice here? Do I create a UserRepository
in the Persistence
project, and just make an entire method called CheckEmail
? Or do I simply add the nHibernate .dll's to my Utilities
project, and write session lookup within the Provider?
It seems like more work to make repositories in my Persistence Project that do specific actions than it is to make the providers. Why am I even making the Providers if I have to make Repositories for them? Isn't the purpose of all of these new methods to stop code repetition? But it feels like to keep things 'separate' I have to write the same code 2 or 3 times. What is the best practice here?
Your repositories should really be implemented in your Persistence assembly. Assuming you are unit testing them, you would define the interface for each repository in your Domain assembly.
Your CreateUser
method shouldn't be directly querying the database to determine if the email address already exists, instead create a separate method in your DoesEmailExist
which is responsible for doing that check. Each method should have a single responsiblity.
In response to jfar's doubts:
That's right, the domain defines what can be done, defining interfaces such as Domain.IUserRepository.Create(User user)
. The domain does not however define any implementation.
Let's say you start out using Entity Framework, you might create a Persistence
assembly which implements the interfaces defined in the domain. So following on from the domain interface above we implement the interface:
namespace Persistence
{
public class UserRepository : Domain.IUserRepository
{
public void Create(User user)
{
// use Entity Framework to persist a user
}
}
}
Let's say for example that your customer later tells you to implement an NHibernate persistence layer. Luckily our domain is separate to the existing persistence layer - it's in the domain. So you can easily implement the existing domain interfaces without needing to change any code in your MVC application - as all that knows about is the interface you defined, not the Entity Framework implementation.
Your IoC container can then be configured to resolve IUserRepository
as either the Entity Framework or NHibernate implementation, your MVC application doesn't care either way.
In terms of assembly references, the Persistence
assembly has a reference to the Domain
, and the Domain
quite rightly does not have a reference to Persistence
.
This leads to a decoupled design which is easy to test, and change going forwards, resulting in easier maintenance.
I hope that helped.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With