This post deals with the tricky issue of creating a data model or domain model as its also known for our MVC 4 application. The first thing you need to decide is whether to use an ORM tool to take care of the persistence layer of your model, i.e. the layer that takes care of the querying and updating of any connected data stores such as an SQL database. Microsoft is really pushing for developers to do this, in particular with the use of Entity Framework. Alternatively, nHibernate is another ORM that many .Net developers choose.
With Entity Framework 5 (EF) chosen we then had to decide how to use it, be that model-first, database first or code first. Without going into the particulars about each approach, you can get all the information you will ever need on it at the official EF site. Needless to say the names of each method are pretty self-explanatory. We decided to go with code-first as a) we did not have a database created already so we didn’t have to go for database-first and b) we where more comfortable, being c# developers, in focusing on creating our database tables by first creating object classes in c# code, which is essentially what code-first boils down to.
As this was our first time working with EF and code-first we found it very tricky to visualize what classes we needed and how they would all fit together.
We found it useful to first sketch out classes and their relationships to one another prior to diving into coding up your model classes. The reason we did this is because once you decide to use EF, you’re no longer creating ordinary MVC model classes, you are creating model classes knowing that EF will be looking for you to follow a set of conventions.
The trickiest convention is possibly the idea of navigation properties. When you sketch the model out into a diagram you end up with objects that are somewhere between an ERD and a class diagram structure, see the diagram at end of this tutorial to see what I mean.
With this in mind you might think, well if we are going to trouble of sketching it out, why not go with a Model-First EF approach. We probably could, but we were more comfortable with the idea of code-first, plus we felt once we sketched out a rough model we would get an understanding of how the classes should be formed and creating any further classes that we didn’t have in our original diagram would become easier to model. We were also eager to get working with data annotations and the fluent API that code-first design offers.
As you can do a lot of customization to your database using Fluent API it was tricky to settle on just how complex we needed our model classes to be. To us, this was a tough balancing act – how detailed do I make my classes in order to aid my database creation, considering I can do a lot of configuration using the Fluent API. I’m not sure there is a right or wrong answer. We just put properties in our classes that we felt made sense for that class, followed the basic conventions around navigation properties and foreign keys, and left everything else to annotations and the fluent API. The code-first approach is very fluid as well as being “fluent”. Using Migrations, it is possible to update your model and database with ease.
After much discussion we settled on a model we felt we could work with, in the knowledge that we would more than likely need to make further updates to it once the Entity Framework got its hands on it. Our lack of EF experience meant that there would be some trial and error involved here, but that was okay, getting your hands dirty is pretty much the best way to learn this stuff, tutorials will only get you so far.
We closely followed the recommended guidelines in setting up the model. We created a seperate class library with the suffix ‘.DomainModel’. In it, our domain classes contained our properties that we would need, including navigation properties, primary and foreign keys. We instantiated any navigation properties that were of type ICollection as this is .Net best practice.
Once that was done we moved on to creating our Entity Framework Data Contexts. We followed Julie Lerman’s advice on creating Bounded DbContexts here. The idea behind this is to use several smaller DbContexts instead of one all encompassing one. This would mean less data being pulled to and from the database when instantiating our dbContexts. However, in order to create the database you need to first create an unbounded DbContext that contains all the classes you want to include in your Data Model. We created a seperate class library for this. We referenced the EF dll. At this point you will have a domain model project, a data layer project (to house your bounded DbContexts) and a DatabaseInitializer project to house a DbContext which contains all the classes mentioned in the various bounded DbContexts. This is the project that will also contain your migrations if and when you use them.
One thing I found confusing is where to put your connection string? Each project that has a reference to EF contains an app.config file with a default DB location. What we did was delete all these configs except the one in our main initial MVC project. In here there is no app.config but a web.config as it is a web project of type of MVC 4. Inside the web.config you will have a connection string setting but also the entity framework default connection factory setting that was in the various app.config files. My understanding is that the connection string that is set in the connections section of the file will supercede anything in the EF section, so that section can be ignored. I will do some tests to check this. Indeed our ultimate goal will be to remove the EF dll from our MVC project so this EF section in the web.config will eventually be deleted. We need to leave to our EF dll there for now to aid with controller and view scaffolding.
Once you have your DbContext built you can have a look at how your Data Model will look in diagram form by using the EF Power Tools extension to create a read-only Data Model Diagram for you. There are instructions on how to use the tool for this purpose here.
Once all of that is done I thought great, now how on earth do I get it to actually create the Database. There seems to be some unique things you should do if doing it in an MVC 4 project.
Firstly, to ease initialization of the database you should firstly enable migrations, even before you create the database.
Enable-Migration -ProjectName “xxx” -StartUpProjectName “yyy”
I used this command as I wanted the migration files that are created to be put into a project other than the main startup project.
I created the database using what I would consider a very crude method. I added some random code to one of the controller actions I knew would be called, all it did was instantiate the database initialization dbContent. If you recall this is the context that has its own project and contains all of the model class DbSets.
I could have just waited until I really actually needed to create some code to access the DbContext, but that will be a while yet as I hadn’t even gotten around to creating the Repositories yet. Anyways this is basically the way you create your database, you need to build the project, then run the project, making sure it makes a call to your dbcontext during execution.
Repositories:
We decided to create a repository for each of our bounded Db Context classes. The tricky bit I found with doing this is that many/most DbContexts contain more than one model entity, what I mean by entity here is an instance of DbSet<DomainModelClassA>. Most DbContexts will contain multiple entities, where as a repository pretty much has to have a focus on a single domain model class. There is very little documentation on this, but from what I can make out, each bounded DbContext should have a main model/main entity, with the rest being supporting models that are useful to have in that DbContext. It should be obvious from most DbContexts which entity this is. If you have a CustomerService bounded DbContext, you will probably have model classes such as Customer, Order, Address as entities in your bounded context. It is clear that Customer is the main focus of this context, so, this should be the focus of your repository and eventually your controller. Then if you need access to the address or the order object you can get to them through Customer as all three are part of the same context. You can always create more than one repository per context if you think that is neccessary. However, if you have a DbContext where you think more than one entity could be your primary repository bound class then maybe you need to look at your DbContext again and look at refactoring it out into 2 seperate DbContexts, or looking at your database/model classes and making sure they are as logically layed out as possible. In the above example you would probably also have some sort of Orders DbContext, which could contain Orders DbSet as well as containing a Customer DbSet. In this instance you would use the Order class as your main repository class. As I said I’ve pieced this together myself pretty much, so there is bound to be other ways around this.
You can use the MvcScaffolding template (get it from nuget) to create controllers, views and repository classes for you. I found it quite good. You just need to make sure to specify a model class, e.g. Customer and then specify the bound Data Context, e.g. CustomerServiceContext. It will create the classes in your MVC project, but you could just copy paste the repository code that it creates into another project if you are putting your repositories into seperate projects. To be honest, our respositories looked quite a bit different from the scaffolded ones, as we were using Units of Work and accessor classes. So instead of using the scaffolding, we created a template class (saved as a .txt file) that we could copy and paste into any new repository classes. It included an interface and accessor class. We found this a better option and I will look to creating a template of this file type to add into visual studio if thats possible, so it can be used on future projects. We may even create our our own mvc scaffolding tool for nuget. We found this approach preferable also in the sense that we wanted ot get our model layer as developed and tested as possible before moving onto creating the controller and views.
Unit of work and accessor/wrapper classes:
We encorporated or encased if you want to put it that way, our repositories in unit of work classes. We then created accessor/wrapper classes to wrap around the unit of work class. The reasoning behind this was to remove any coupling between the controllers that we would create and the MVC project in general and our EF data contexts. The Unit of Work class that we created expected a DbContext type to be passed to it, e.g. new UnitOfWork<CustomerBoundedContext>(). If you use only one context you will only need one UnitOfWork class, e.g. new UnitOfwork(). However, as we had multiple contexts we needed to create a unit of work that could work with any and all of them, hence the generic Unit Of Work. The problem with this is, if you reference the unit of work class inside a controller, then you must also reference a DbContext, which means the controller must know about the contexts and the EF. We didnt want this, hence our use of accessor classes. By placing the UnitOfWork object instantiation into a wrapper class in that same project, we then only had to expose that class and only that class to the controllers, in other words, the controller did not need to have any knowledge of the entity framework’s existence.
Coming up Next: Dependency Injection and Inversion of Control
So thats basically it in terms of creating our domain model using Entity Framework 5 code-first. It feels great to have it done, even though in reality it will almost certainly turn out to be the first of many iterations of the domain model. But even still, it feels like we took a big chunk out of our development work. This blog entry isn’t all that heavy on the exact details of what our classes look like our how we split up our model into multiple projects. If you are interested in the approach we outlined but would like a little more info, I would be more than happy to answer any queries you might have on this.
In our next post we will look at how we can best implement hooking up our model to any new controllers that we create. Spoiler alert, it involves Dependency injection and Inversion of Control using Ninject!