Getting Started with Highway.Data.EntityFramework
So you want to get started with Highway.Data, but dont know where to start? That is what I am here for. I am going to be your guide to this awesome framework. We are going to start off with something simple and then add to it. You ready? Awesome!
First thing we want to do is create a new project. I am going to create a console application because it is easier to demo that way, but feel free to use this approach in what ever project you are working on.
There is nothing special about this, but we want to open up the Package Manager Console to install Highway.Data.EntityFramework into this application.
We do this by typing the command Install-Package Highway.Data.EntityFramework
We are not going to bring in an Inversion of Control Container yet, but we will. That walk thru is here. ( link to come )
I get this when installing, your might be different version numbers.That is simply that I am stuck in time, and you are not.
Once we have this installed we are now ready to map our database so that we can jump on the Highway and cruise.
We need a class called GettingStartedMappings that implements the Highway.Data.IMappingConfiguration. This allows us to use the normal Entity Framework mappings to talk with our database. This is no different now than what we would put in the OnModelBinding event on DbContext. Documentation here (http://msdn.microsoft.com/en-us/library/gg696169(v=VS.103).aspx).
We are going to map a couple of tables. I am going to map one Person in line, like so:
This maps using the fluent configuration to specify the key and the table name. Anything that adheres to the standard convention doesnt have to be explicitly set.
I am going to extract the person class from the mappings simply to make our lives easier. So it should look like this.
This would be the second way to approach this. I feel this is the better approach because it is more segregated for each entity having its own file. We are going to create a new class file for AccountMap.cs and a new class for Account.
The AccountMap is going to inherit from System.Data.Entity.ModelConfiguration.EntityTypeConfiguration<T>. This is the EntityFramework built in mapping configuration that allows you to segregate your mapping by entity type. Documentation (http://msdn.microsoft.com/en-us/library/gg696117(v=VS.103).aspx)
Notice how we are able to do each entities mapping in a separate file. All we then have to do is register this into the mapping configuration. Like so:
That gets us configured but we still want to be able to use the framework right? Right!
We need two things to talk to the database in the Highway.Data way. A context (this keeps the information about the database and current object state), and a repository (this gives us a mock-able and testable separation between our DB and our logical code.)
You are lucky enough to be using a framework developed by lazy guys, we hate having to right classes just to inherit other classes so we prebuilt a context and a repository that have their dependencies injected. You know, like it is supposed to be.
We will create our context first, for this we need a connection string (just a normal connection string, no meta data here), and our mappings.
We can use this as is, but we would lose the gloriousness that is repository pattern, and that is bad mmkay! (http://www.martinfowler.com/eaaCatalog/repository.html)
With our repository it should look like this.
This is the basic start to using Highway.Data.EntityFramework. It is beautiful, simple, elegant, and USELESS!!!
We need to be able to add data and save data right? So lets to do that. Remember that the context is what knows about the database so who do you think is going to have the control of add and save? RIGHT, the context!!
Lets add the people that made Highway.Data what it is today,and commit that to the database, shall we?
This is pretty slick right, but Devlin you say, How can I query objects back from the database?. That is easy, but we have to explain something, it is important I promise. Do you like embedding SQL into your web pages? No, why not? Oh, it is a separation of concerns issue? I agree. So is that any different that putting LINQ everywhere? No, I dont think so either. So we need to isolate our Queries so that we can be more encapsulated. We are going to write a query for finding a person by last name.
We need a new class FindPersonByLastName that inherits from Highway.Data.QueryObjects.Query<Person>. This gives us the base implementation to make the Command Query Separation that is built into the Highway work.
Notice that we set ContextQuery and store a delegate ( lambda ) statement here. This allows us to keep defered execution and still parameterize the constructors of these query objects. I like this approach because paging and sorting are built into the object. We can re-use this without concern for breaking existing code. Open-Close principle is AWESOME!
When we go to use this, we now just have to pass our query ( or if you like the technical term, our specification ) into the repository and it will execute it on the data needed, without being aware of the details. ( Specification pattern - Specifications - Martin Fowler)
I also want to call your attention to a subtle but important detail. Notice that the results is an IEnumerable<Person>. This means that while we have not broken the deferred execution of this chain of LINQ statements, we have sealed the SQL statement at the point of return. Anything you add outside the query object will not change the dataset returned. You can tack on paging like the example below.
Now that we have data back, we want to modify and commit those modifications. Really, too easy!!
But, Devlin my DBA wants me to fix this slow query and make it a stored proc! We have that covered too! All you have to do is change the query, not other changes needed.
The one restriction to this is that the stored procedure needs to return the columns with the right name, type and order to map to the object. This is because we are doing some mapping magic. Injectable mapping is something we have concidered but havent seen enough requests for.
But, Devlin I want to call a query that only returns one person. I dont want to deal with IEnumerable<Person> Thanks for the easy one, just use Scalar<T> and while we are talking about it, how about something without a return, like a stored procedure call.
We use these in the same way we use a query. Pretty slick huh?
Well that is a crash course on Highway.Data.EntityFramework. There are WAY more features. Those walk-thrus are coming, but until then.
Hop on the Highway and see where it takes you
Authors and Contributors
This framework was created and is maintained by Tim Rayburn (@trayburn) and Devlin Liles (@devlinliles)
Feel free to open issues on GitHub if you encounter any issues. If you need a commercial support license, then feel free to contact us at email@example.com and we provide you pricing for these options.