This chapter will cover the third approach, the code-only approach, which provides developers the ability to use the Entity Framework using POCO entities and without an EDMX file.. 168 •
Trang 1167
Code-Only Development
When Microsoft set about to make the Entity Framework more flexible, their goal was to provide
developers with an environment in which they could create their model from one of their approaches The first approach, which has existed since the initial release of EF, is the ability to generate your model from a database Many of the chapters in this book have covered the new features and concepts that are tied to this approach
Chapter 9 covered the second approach, model-first, which lets developers start with a conceptual model and generate their database based on that conceptual model This approach also lets developers customize DDL generation through T4 templates and Windows Workflow, giving them the utmost
flexibility and control over the creation and generation of the DDL This is truly a “model-first” solution This ability to customize is a giant step over EF 3.5, in which you could define your conceptual model in
EF but not do anything beyond that, such as generate your database
This chapter will cover the third approach, the code-only approach, which provides developers the ability to use the Entity Framework using POCO entities and without an EDMX file This approach lets
developers view code as their model There is a lot of discussion around the code-only approach, such as whether code-only will contain much of the functionality found in a standard EDM model approach
The goal from the outset was to ensure that most, if not all, of the functionality found in the other two
approaches (model-first, database-first) is found in the code-only approach This includes topics such as deferred/lazy loading, change tracking, and complex types And let’s not forget new foreign key
association support This is included as well
In this chapter we will cover the code-only approach and discuss many aspects of building an EF
project using code-only We will build a simple example, and we will also discuss some of the other
aspects that you can add to your code-only project, including deferred/lazy loading, complex types, and change tracking
Let’s get started
Getting Started with Code-Only
The first thing you need to do is download a feature preview from the Microsoft website In your favorite browser, go to the following URL:
http://www.microsoft.com/downloads/details.aspx?familyid
=13FDFCE4-7F92-438F-8058-B5B4041D0F01&displaylang=en
The ADO.NET Entity Framework Feature CTP is a set of features that adds additional features and components to EF 4.0 From this website, click the Download button, which downloads a file called
EF4FeatureCTP2.exe The ADO.NET Entity Framework Feature CTP installs the following components:
• Templates for self-tracking entities (used for N-Tier support we’ll use this in
Chapter 11)
Trang 2168
• Code-only programming model used with the Entity Data Model
Make sure Visual Studio is not open when you run the installation When the installation is complete, we are ready to begin
Creating the Data Project
In Visual Studio 2010, create a new Class Library project I called mine CodeOnlyData, as you can see in Figure 10-1 The CodeOnlyData project is the data project that will contain the POCO classes that will mimic the EDM
Figure 10-1 Create class library project
Once the project has been created, delete the Class1.cs class and add two additional classes:
• Contact.cs
• Employee.cs
We are ready to add code The Contact and Employee classes are our POCO classes and are
essentially called POCO entities Let’s work with the Contact class first Open the Contact class and replace everything in that class with the following:
Trang 3public int ContactID { get; set; }
public bool NameStyle { get; set; }
public string Title { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public string Suffix { get; set; }
public string EmailAddress { get; set; }
public int EmailPromotion { get; set; }
public string Phone { get; set; }
public string PasswordHash { get; set; }
public string PasswordSalt { get; set; }
public Guid rowguid { get; set; }
public DateTime ModifiedDate { get; set; }
public ICollection<Employee> Employees { get; set; }
}
}
This code is our POCO class for Contact If you were to look at an EDM generated from the
AdventureWorks database for the same table, you would see that this nearly matches the CSDL entity
type with many of the properties It’s as simple as that
Now for the Employee class Open Employee.cs and replace the code in that class with the following:
public int EmployeeID { get; set; }
public string NationalIDNumber { get; set; }
public string LoginID { get; set; }
public Nullable<int> ManagerID { get; set; }
public string Title { get; set; }
public DateTime BirthDate { get; set; }
public string MaritalStatus { get; set; }
public string Gender { get; set; }
public DateTime HireDate { get; set; }
public bool SalariedFlag { get; set; }
public short VacationHours { get; set; }
public short SickLeaveHours { get; set; }
public bool CurrentFlag { get; set; }
public Guid rowguid { get; set; }
Trang 4170
public DateTime ModifiedDate { get; set; }
public Contact Contact { get; set; }
//public int ContactID { get; set; }
}
}
This creates our POCO class for the employee At this point we are pretty much done with our data project We haven’t defined any relationships or configuration items, but we will do that shortly in a second project, and I’ll explain why we do it there when we get to that point So, let’s build our UI project
Adding the User-Interface Project
We need a UI project that will consume our data project, so let’s add that From the file menu, select Add
➤ New Project When the Add New Project dialog opens, select Windows from the list of installed templates, then select Windows Forms Application from the list of templates Name this project
CodeOnlyUI and click OK
You might be asking why we created a separate project for our POCO classes The answer is simply because we want several things First, this allows us to compile our classes into a separate and distinct assembly from the UI project Second, and most important, is that this allows us to keep the data assembly persistence-ignorant
Adding References
Here is where the ADO.NET Entity Framework Feature CTP comes in to play We need to add a few references to our UI project Right-click on the references node in Solution Explorer for the CodeOnlyUI project When the references dialog displays, we need to add two references to this project They are the following:
• System.Data.Entity
• Microsoft.Data.Entity.Ctp
Figure 10-2 shows the Microsoft.Data.Entity.Ctp component selected in the Add Reference dialog This is the Code-Only Programming Model component Select these two components and then click OK
Trang 5171
Figure 10-2 Adding feature reference
Why do we need a reference to the Code-Only Programming Model component? If you look at the properties of either the System.Data or Microsoft.Data.Entity.Ctp assemblies you will notice that they
point to a location that is different from the System.Data assembly in your data project Your
System.Data component in your data project (CodeOnlyData) points to the following location:
C:\Program Files(x86)\Reference Assemblies\Microsoft\Framework\.NetFramework\v4.0
The System.Data and Microsoft.Data.Entity.Ctp assemblies in your UI project (CodeOnlyUI) are
located here:
C:\Program Files(x86)\Reference Assemblies\Microsoft\Framework\.NetFramework\v4.0\
Profile\Client
The client profile target framework allows you to create an assembly that only needs the smaller
subset of NET 4.0 assemblies, which is in the client profile If all of the assemblies in your application
target the client profile target framework then this will allow you to install your application on a client
computer with a very small footprint, and download and install only the smaller components
We also need to add a reference to our data project within our UI project Right-click on the
references node again in Solution Explorer for the UI project, and select Add Reference When the Add References dialog opens, select the Projects tab and select the CodeOnlyData project, shown in Figure
10-3 Click OK
Trang 6172
Figure 10-3 Adding project reference
Adding Context and Connections
At this point we have a simple code-only “model” via our POCO classes, and the beginnings of our UI application What we don’t have yet is our context and connections or any configuration components that define relationships and associations, so let’s add those now
Add the following three classes to the UI project:
• AWModel.cs
• ContactConfiguration.cs
• EmployeeConfiguration.cs
When we are all finished adding everything, our Solution Explorer should now look like Figure 10-4
Figure 10-4 Solution Explorer
Trang 7173
Coding the User Interface
It is time to start adding code to our UI project Open AWModel.cs and replace the code that is there with the following:
Creating Configuration Classes
The next step is to create our configuration classes and methods, one for Contact and one for Employee Open ContactConfiguration.cs and replace the code in that class with the following:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
Trang 8on a single line instead of two separate statements The PasswordHash and PasswordSalt properties show this
Let’s do the Employee next Open EmployeeConfiguration.cs and replace all the code that is there with the following:
Trang 9In this code, we define the identity for the Employee and set the MaxLength and IsRequired
properties as we did with the Contact class However, we also did a couple of other things First, we
define the relationship between Contact and Employee, and second, we set the relationship as required Thus, we have just defined the PK association
Testing the Code-Only Model
Let’s put this code to good use and test our code-only model Open Form1 in design view and drop a list box onto the form In the code behind the form, replace the code with the following:
var context = builder.Create(conn);
var query = from c in context.Contact
select c;
foreach (var con in query)
Trang 10var context = builder.Create(conn)
Where did the ContextBuilder come from? It was installed as part of the ADO.NET Entity Framework Feature CTP and exists in the Microsoft.Data.Objects.ContextBuilder class This class infers the Conceptual Model, Storage Model, and Mapping, using the metadata and the SqlConnection to create
an EntityConnection
Building the Project
Build the project to ensure there are no errors, then run the project by pressing F5 When the form displays, the list box will populate with the first name of all the contacts, shown in Figure 10-5 The form isn’t very effective, but the purpose of this example isn’t form functionality here We’ll make
modifications shortly to add more functionality Also, feel free to modify the query to experiment with this example
Trang 11177
Figure 10-5 List of contact first names
This example isn’t very efficient because we are not filtering on anything, so we are returning a lot of records (nearly 20,000 to be exact) The form may take several seconds to load Again, we aren’t going
after prettiness, but functionality of code-only
Loading Some Rows
Let’s continue this example by adding some code that will use the Employee entity Stop the application and open the form in design view, and place a DataGridView on the form below the list box
The first thing we need to do is modify the code so that it is more usable throughout the form To do that, add the following three lines in the declaration section The first line simply defines a variable so
that we know whether the form is loading The second line defines an SqlConnection variable, and the
last line defines a ContextBuilder variable based on the model we are using
bool isLoaded = false;
SqlConnection conn;
ContextBuilder<AWModel> builder
Next, we need to modify the code in the Load event of the form so that it is not loading all 20,000
rows—we just want a specific subset of that Therefore, modify your code in the Load event to look like the following:
Trang 12ValueMember properties The DisplayMember property identifies which value in the query to display in the list box The ValueMember sets the property to use as the actual value of the items in the list box
Connecting the DataGridView Control
Our next step is to wire up the DataGridView control We do this by adding the following code to the SelectedIndexChanged event of the list box
Trang 13related Employee data; then, like we did earlier, we bind the query to the DataSource property of the
DataGridView control
Running the Application
Once you have added the code, run the application When the form displays, it will list the first name of everyone from the Contact table, in alphabetical order, whose last name begins with the letter G Scroll down in the list until you see those contacts whose first name is Scott Select the second Scott This
contact’s Employee information will then display in the grid, as seen in Figure 10-6
You will notice that I have added a label on my form that displays the ContactID of the selected
contact You’ll also notice that as you select other names in the list box that their associated Employee
information does not display in the grid That is because they don’t have any Employee information Our query in the Load event doesn’t look for contacts who have related Employee information We can fix
that by joining the Contact table to Employee table as follows:
var query = from c in context.Contact
join emp in context.Employee on c.ContactID equals emp.Contact.ContactID
where c.LastName.StartsWith("G")
orderby c.FirstName
select new { c.ContactID, c.FirstName, c.LastName };
This query will return only eight rows because we are still looking for contacts whose last name
begins with the letter G Comment the where clause out in the query to remove the query filter
Trang 14180
Figure 10-6 Contact and Related Employee Information
Through these examples you can see how easy and flexible the code-only approach is compared to database-first and model-first
Overcoming Restrictions in EF 3.5
When dealing with entity classes with EF 3.5, developers were faced with some restrictions that made it fairly difficult for developers to implement EF-friendly technology These constraints included the following:
• Developers needed to implement IPOCO interfaces such as IEntityWithKey,
IEntityWithChangeTracker, and IEntityWithRelationships
• Entity classes needed to be sub-classes of EntityObject
These restrictions made it difficult for developers to build domain classes that were ignorant, requiring developers to inherit and implement interfaces and base classes that were needed for persistence
persistence-EF 4.0 overcomes this by utilizing the Entity Framework to query these instance types simply by using POCO, getting all of the regular EF functionality such as change tracking, FK associations, lazy loading, and complex-type support automatically
The next section will talk about these features in detail and how to implement this functionality using POCO
Additional POCO Information
Microsoft put a lot of effort into supporting POCO in the Entity Framework They wanted to ensure that your experience with POCO would be a good one, and, therefore, they made sure that much of the functionality you get with the other facets (model-first and database-first) are also found in code-first This section will discuss using complex types, lazy loading, and change tracking