Tuesday, October 30, 2012

Part 2 Entity Framework 5 using the POCO pattern, a data first approach, for a Table Per Hierarchy model

*Disclaimer these writings are for my own learning purposes not as advice to others. If any part is incorrect please feel free to constructively discuss.

Part 2: MVC 4 with existing context class, and an abstract base type

Previously in Part 1 I discussed a data first approach to using Entity Framework, existing POCO's, and a table per hierarchy design.

With all that wired up I began to evaluate MVC 4.

Most MVC tutorials will have you start off with a table first approach or an object first approach. In the case of a table first approach you will end up with a datamodel (edmx file), and they will let EF code generate entity classes inheariting from EntityObject and a context class inheariting from ObjectContext. Some tutorials even advise that these entities might be a tad heavy for some uses. The alternative is to use DbContext by right clicking the model and choosing "Add code generation item", and selecting "ADO.NET DbContext Generator". This leaves you with a much more simplified context class inheriting from DbContext that just returns sets of each entity. You also get a much more stripped down simple entity class definitions.

I did not used EF code generation but instead defined my own entities and context class. (This will come into play later).

After adding an MVC app to my solution and choosing Razor as my view engine, I first needed to create a controller. In the "Add Controller" prompt you have the ability to choose a controller template that will wire up read/write actions and views for you. All you need is a model class and a context class.

If you choose this option you end up with a BookStore controller that already has the actions wired up for you.
You also get a class level instance of your context object instantiated in the controller.
Also notice the Get and Post verb comments added, (More about that later).



Also you get all your Razor cshtml views created for you.













This is enough to start the MVC application and view the default layout that comes with it.
Notice the RESTful URL style, and seperate views representing basic CRUD operations.



But there's a small problem. If I go to POST Or GET on one of my resources (create or an edit) I get this big ugly error.

Server Error in '/' Application.

Cannot create an abstract class.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.MissingMethodException: Cannot create an abstract class.




Why am I getting this? Pretty simple you cannot instantiate an abstract class. MVC has these ModelBinders, and I'm no expert but in simple terms they help bind the model information to the views. The default model binder may realize it needs a Book object but remember that discriminator thing we talked about in Part 1? The default model binder doesn't know how to make this discrimination. But we can define our own ModelBinder. To do that you need to derive from DefaultModelBinder. I'm only going to override the CreateModel method. Here is the result. 



But, we aren't done quite yet. I needed to tell the application to use this new binder before it worked correctly. You do this in global.aspx. 

Now that I have defined my custom modelbinder and added it to the global.aspx I can run the site. Its still just a very out of the box MVC 4 application. Notice the default edit and create views that got made for you. They don't reflect all the properties in our objects.





















My enums are missing. This may be because of how we had to map the entities, but fixing is pretty easy. I added the following lines to use the DropdownListFor control in the html helper



This control requires a SelectedList of values. You can add the C# required to accomplish this directly in your cshtml page using the open and close tags like @{ }

Instead I added a static method to the book class. that looks like so.


Technically putting this functionality in the Book class is all kinds of wrong, and I would not actually do this in  a production application. The reason not to do this is I would be breaking the "separation of concerns" principle by bringing a UI concern into a domain object. This whole demo app could be structured so that my UI layer doesn't even know about my domain objects. A service layer could pass the UI layer nice flat DTO's. I could then add this method to the Book DTO. 

In the end I end up with something that represents all the elements ofthe book object I need to do a create. 





















Obviously this is still not in a state I can really use. No one knows what ReturnPolicy value 3 means. To handle that I can decorate my Enum's with the Componentmodel.DescriptionAttribute and alter my EnumToSelectedList method so that the SelectedListItems text value pulls the description attribute. That's outside the scope of this blog but if I get around to writing it I will edit this blog and add it.

More to come in:

Part 3: MVC 4 view engine, Observer Pattern, and binding


No comments:

Post a Comment