Why use Entity Framework?
I will not extend this blog with a long introduction about ERMs, EDMs, ORMs and other theories behind E.F., but you can easily search the internet for these concepts.
If you believe Microsoft, Entity Framework is a change that will get you programmers concentrate on your applications, and never again have to be concerned with trivial things such as the details of a database or the intricacies of an SQL script.
Unfortunately, this 'increase your productivity and your developper experience' is something that you have already heard in the past, with DAO, RDO, ADO, ADO.NET, and Linq. And you are probably not sure if you need another langage to query your data Edit : see Joe's Babel tower blog published just after this one.
But the good news this time, is that E.F. will not replace any of the data access techniques that you learnt before. Either inside, or beside E.F., you can still use Datareaders, Datasets, SQL scripts, Linq queries and the DNN data layers if you want. Although you don't have to in most cases.
To give a simple example of the E.F. model, you can consider the traditionnal Orders and Details objects, with their related Products, Customers and Categories tables. Obviously, a single SQL query cannot return the basic data that we as human beeings understand as an 'invoice'. At best would it return an hyper redundant set of virtual rows, each of them containing the customers adress and the invoice number. Returning this data in a single query would require a terribly long and complicated script, involving several JOINS.
Entity Framework can easily return exactly the data that you call an invoice : one name, one adress, one date and number, several rows including products, prices and there category names.
E.F. benefits : DRY and Convention
Apart from the Object model, I can see at least three other benefits from using Entity Framework.
One is the Ruby on Rails concept of Don't Repeat Yourself (DRY). Since the relations between one order, one customer, many detail lines related to one product, have been defined through tedious declarations like:
ADD CONSTRAINT
FK_Store_OrderDetails_Store_Orders FOREIGN KEY (OrderID)
REFERENCES Store_Orders (OrderID)
why would we have to explicit these same relations again and again in our scripts, our program and our controls properties ?
Second benefit is Conventions. Just like DNN invites you to adopt a similar syntax for you CRUD operations, for example 'Store_Products_AddProduct' and 'Store_Categories_AddCategory', Entity Framework will suggest a common set of classes for all the CRUD operations for all your projets for all your tables. Moreover (like RoR), it will create the classes and there methods for you. In this case it would be:
Public Shared Function CreateStore_Products
and
Public Shared Function CreateStore_Categories
The third benefit is filling the gap between Windows and Web development, with greater similarities in the data models.
Prerequisites
The following demo assumes:
1. A DNN portal with MSSQL
2. The Store module installed
3. NET framework 3.5 SP1
4. Visual Studio for WAP projects
It is also recommanded that you read my march 1st blog: 'setup a VS project', wich describes Gilles's technique to start a module. This will help if you want to package this exercice into a true DotNetNuke module. It is not a requirment though. You may perfectly discover Entiy Framework with a external project that will query your Store data from outside DotNetNuke, as an external management of the store for example.
Creating our Entity Framework Class Library
1. Add a project using Visual Studio 'Class Library' template. Make sure that it will target .NET Framework 3.5
2. Name it 'StoreModel'. Delete Class1.vb (or Class1.cs)
3. Make sure to add references to System.Data.Entity and System.Web.Entity
4. Rightclic the project, and Add a new item using ADO.NET Entity Data Model template
5. Name it 'StoreModel.edmx'. This should start a wizard
6. Select 'Build from Database' (or similar - back-translated from my french VS2008).
7. Select the connexion to the database that contains your Store Module
8. Check 'Save the entity connexion parameters in App.Config as ...
9. and name it StoreEntities
10. Note the connexion chain that has been generated for the Entity. The interesting part there beeing the StoreModel.csdl, StoreModel.ssdl and StoreModel.msl substrings.
Enough for now to know that these are three different files that will be compiled with our model. These files are the three parts of our entity model:
- .csdl (for Conceptual Schema Definition Language), describes our Objects (think of an Invoice). It's the C-side
- .ssdl (for Store Schema Definition Language), describes our database tables structure. It's the S-side
- .msl (for Mapping Specification Language),is the link: the C-S mapping
But let's not divert from our Hello Entities Demo, and let's click Next.
11. The wizard should now ask to select your database objects. Expand the Table List and select the Store_ tables. No need for views since Entity Framework will bring the same query fonctionnalities than views, in a more elegant and efficient manner. As for Stored Procedures, we might want to reuse some of them, but we don't have to. Let's just Finish with our 11 Store tables selected.
12. Done. The wizard will create the model. If you clic StoreModel.edmx, you will have a design view of the model that pretty much looks like an SQL database designer schema.
Look at it carefully though, and you will notice meaningfull differences. Under every Entity (we don't say a 'table' here since we are in the C-side !), you will see 'Navigation properties'. This means that the data that is relevant to an entity (for examples the OrderDetails for an order), belongs to it although it in in another Database table in the S-side. Similarly, Store_Orders is a 'Navigation property' of the Store_OrderDetails Entity, because it is of interest for a detail line to know which Order it belongs to.
At this stage most programmers drag the entities accross the page to see how the designer reorganises the schema ! I understand they need a pause, but there are more interesting things to do: inspecting the model's XML.
13. Rightclick 'Open with' on StoreModel.edmx, select XML editor. You will be required to close the visual model: accept and the XML file will show up. Notice that you will find here the three Model parts that I mentionned at step 10.: -- SSDL content -- !-- CSDL content -- and -- C-S mapping content --and These sections are the most interesting ones when you want to create more complex and powerfull models. The second part is just the designer content - what you changed when you played with your mouse moving the entities visually.
14. When the project is compiled, you will not see physical .csdl, .ssdl and .msl files, because they are embedded into the assembly by default. You can change this behavior in StoreModel.edmx properties, by selecting 'Copy to Output directory'. In this case the three files will be built separetely as normal XML files that you can read or edit outside Visual Studio.
Our first Hello Entities DotNetNuke Module
15. Create a new Project using Visual Studio WAP template. Name it StoreEntities.
16. If you wisely decided to adopt Gilles's technique to start a new project (see our previous blog), you would now have 3 projects in your StoreEntities solution: a.- a http://localhost/DotNetNuke_2/ b.- the StoreModel Class Library we built earlier c.- our new StoreEntities project
17. Make sure that all 3 projects above target the 3.5 .NET framework (properties / compiler / advanced options)
18. Delete the web.config that sometimes autogenerates in one of the projects folder
19. Add the Project reference StoreModel to your StoreEntities project
20. Copy the connexion string for the Entity Framework into your DotNetNuke web.config (add it to the database connexion string that is already there, but delete nothing ! the good old database connexion connexion string is still usefull for a couple of things in your DNN portal ! You may make use of the string that you copied at step 10 ; or copy the connexion string that you will find in the App.config file in the StoreModel Project. You may replace the database substring with the credential parameters that are already used in your web.config. The resulting string might look like:
21. If you started from the DotNetNuke compiled module template, do some house cleaning and delete all the things that we won't use: the data access layers, the documentation folder, the EditStoreEntities, and the controls and code inside the ViewStoreEntities.ascx and ViewStoreEntities.vb (or cs)
22. Drag a GridView onto your page (you may prefer to create your data source first, and then bind it to a control, but if you drag the GridView directly the wizard will create an EntityDataSource for you - this is a good choice for a HelloStoreEntities demo).
23. Open the GridView task menu, New Data Source, Entity, and select StoreEntities. The wizard founded it in the web.config, so if you do not find it in the list, check step 20.
24. Select any of the Store Entities, e.g. the Products table - sorry, the Products Entity (we're on the C-side now where people speak Conceptual Language, not database jargon, although at the stage of a Hello tutorial, they sound pretty much the same)
25. Select the fields - (sorry, the properties), you want in your DataGrid. There is a little detail here. Notice that you won't find a CategoryID property. This is because CategoryID is useless in the C-side. CategoryID only exists for JOINS and database relations, which are now hidden to you. If you need to know something related to the product's category, you will just have to query the Product's Categories Navigation Property itself, and not worry about how to get that. But then, you way ask why there is a PortalID property. Shoudn't the Model know how to reach the Portal Entity, without us beeing aware of the existence of a PortalID key ? The reason is that I didn't include any other tables that the Store tables at step 11. Another reason might be if I included the other tables, but there was not a relational constraint in the SQL schema. In this scenario, the Orders entity would not be aware of it's relation to the Users Entity, even if I had included both tables in my Entity model. This is because Gilles had to disable the constraint between Orders and Users, to prevent errors when quering the Orders history for a deleted user, so this relation is something we'd have to insert manually in our Model.
25. Note that if you choose to select all properties in your EntityDataSource, you would be offered to activate Inserts, Updates, or Deletes - a hint about the CRUD capabilities of our Entity Framework.
Working with relations
Although this is a very short introduction to Entity Framework, I could not stop here without demoing at least a basic relation between entities. We are now going to link a Grid of Products to a Categories DropDownList, so we can select the Products we want.
26. Open a new Web form, and drag a DropDownList. Create a new EntityDataSource, select the Store_Categories Entity with all fields. Select the CategoryName for DataTextField and CategoryID for DataValueField
DataSourceID="EntityDataSource2" DataTextField="CategoryName"
DataValueField="CategoryID">
27. Drag a GridView, create a new EntityDataSource, select the Store_Products Entity with all fields. Add some Visible="false" for the many fields you dont' want into the grid (selecting all fields even if you only display a few of them will be much easier at the beginning, and will let you test the CRUD options)
asp:EntityDataSource ID="EntityDataSource3" runat="server"
ConnectionString="name=StoreEntities" DefaultContainerName="StoreEntities"
EntitySetName="Store_Products" AutoGenerateWhereClause="True"
28. Add the WhereParameters element. The WhereParameters lets a DataSource control filter the data based on the value of another control. It must be embedded between the asp:EntityDataSource tags.
27 Add the AutoGenerateWhereClause="True" property to your EntityDataSource:
ConnectionString="name=StoreEntities" DefaultContainerName="StoreEntities"
EntitySetName="Store_Products" AutoGenerateWhereClause="True">
28. Add the WhereParameters element. The WhereParameters lets a DataSource control filter the data based on the value of another control. It must be embedded between the asp:EntityDataSource tags.
29. Done. No stored procedures, no data layers, no joins: the model knows what it has to do.
Customizing the model
You may wonder where the Vintage column comes from, since it does not exist in the Store module. In fact, my demo shop sells wines, and we needed a property for the year of the wine, rather than the native ModelNumber. So to demonstrate the loose coupling between the database and the Conceptual model, I have renamed de ModelNumber as 'vintage'. Of course nothing has been changed in the database.
Is Entity Framework here to stay ?
Microsoft has expressed strong commitments that it's data strategy is focused on conceptual models. The Entity Framework is the conceptual tool for .NET.
When Microsoft France opened an Open Source competition to replace their aging Sharepoint intranet, they made it clear that using one of their key technology would be the main criteria to select the winner. I think that if Gilles and myself won the contract, it was partly because we prooved them the existence of strong Open Source projects on the Windows stack, but also because we were able to show them the first real Entity Framework application they had ever seen. We're proud that we could help Microsoft increase their productivity and get a better user experience with DotNetNuke.
Will the StoreModel Class Library be included with Store ?
Not with Store v 2.2 that will enter the release tracker in the coming days. Entity Framework requires .NET Framework 3.5 SP1. If we decide that an Entity Framework Class Library may help developpers leverage the potential of the Store module, it might make sense to include it in a future .NET framework 3.5+ / DotNetNuke 5.x / Store 3.x generation.
As usual, your comments are greatly appreciated.