Entity Framework 4, Beta 2 Is Here

Foreign keys, stored procedure improvements, and changes to the EntityDataSource control are among the highlights to expect in EF 4

In "Renovations to .NET 4.0's Entity Framework," November 2009, I wrote about a slew of new Entity Framework (EF) 4 features that I was excited about. The article was based on the Beta 1 version of Visual Studio 2010. Beta 2 has finally arrived with some of the expected additions as well as some others that were a nice surprise.

The Beta 2 version of Visual Studio (VS) 2010 and .NET 4, including the EF, is now fairly close to what the final product will be. This article is aimed at bridging the gap between Beta 1 and the release of EF so that you will know what to look for.

Finally, Foreign Keys
As promised by Microsoft, the foreign keys have arrived in the Entity Data Model (EDM). This is an important feature that impacts much of what you do with the EF, so we'll take a close look. The EDM is based on entity relationship modeling (ERM), which does not expose the foreign keys to related objects as a scalar property. Version 1 of EF subscribed closely to this model, where rather than the foreign key ID, you had to work directly with the related object, aka a "value object" in the domain-driven development world.

There are a number of scenarios where not having direct access to the foreign keys caused developers grief. ASP.NET applications rely heavily on foreign keys in the markup and in the code when working with related objects. In certain situations, associations created problems with related objects that had come across tiers. There was also a very common problem for developers when trying to define a relationship where the value object was not instantiated. For example, if you wanted to define a default Customer Type in a Customer entity, many of us are used to simply the default value—for example, 1—to a CustomerTypeID property. However without that foreign key property, EF version 1 required you to code up one of a number of workarounds that did not align with typical coding practices.

The EF team has written about the introduction of foreign keys into the model on their design blog, but that feature didn't make it into Beta 1. In Beta 2, you can see right away in the wizard (Figure 1) that there is a new check box, Include foreign key columns in the model. This is checked by default when you create a model with the wizard. The Entity Framework team believes that most developers will want the foreign keys as properties in their entities.

Figure 1: The new foreign key option, checked by default, in the EDM Wizard
 
The model will look similar to what you're used to except for the addition of the extra property. Figure 2 shows entities created from the AdventuresWorksLT database, Customer and SalesOrderHeader. The association line between the two still exists as do the navigation properties. The only visual difference is that the CustomerID is now included as a scalar property.

Figure 2: Including foreign keys in models with navigation properties
 
Digging a Little Further
As you might expect, the CustomerID property is mapped directly back to the CustomerID column in the database table. What is very different is how the association is defined. If you're familiar with association mappings from version 1, you may recall that the mapping is where the table's CustomerID foreign key came into play. Figure 3 shows the mapping for an association where the CustomerID foreign key is not included in the model.

Figure 3: Association mappings when there are no foreign keys

This was the only option in EF 1.0 and is now referred to as an independent association. The mapping shows that the CustomerID property in the Customer entity (circled in red) maps to the CustomerID column in the SalesOrderHeader database table (circled in yellow). You can still use independent associations in VS 2010, which means that models and applications you created in VS 2008 will still work properly.
 
When the foreign key is present in the entity, there is no longer any association mapping. If you were to right-click the association line, you will no longer find an option to show the mapping. If you open the Mapping Details window and point to the association, you'll see only this message in the mapping window: Mappings are not allowed for an association over exposed foreign keys. This new association is referred to as a Foreign Key association, and you can find more information about it in the Properties Window. The Properties Window for an association has a new property called Referential Constraint, shown in Figure 4.

Figure 4: The new Referential Constraint property for an association 

Although the window shows that the Customer relates to the SalesOrderHeader, it still does not show you how the foreign key ties to the customer entity. Click the value to reveal an ellipsis that will take you to a more telling window where you can define (or view) the constraint in more detail, as Figure 5 shows.

Figure 5: Definition of a Referential Constraint
 
This constraint refers to the CustomerID property in the Customer entity and the CustomerID property in the SalesOrderHeader entity. That is how the association between the two is now defined. It also defines the constraint that's checked when it is time to save the entities back to the database, just as EF does when you're using independent associations.

When an entity includes a foreign key, the model relies on that foreign key to work out the relationship to the entity on the other end. This is referred to as a foreign key association. I won't bore you with the raw XML of the model, although that is where my personal interest lies when learning how the model is structured.

Now that you see how the foreign keys work, what can you do with them? When you work with the entities, you'll find that the EntityReference is still created, just as it is with independent associations. The (default) generated SalesOrderHeader class now has the Customer navigation property, the CustomerID scalar property, and the CustomerReference property, as Figure 6 shows.

Figure 6: A navigation property, a foreign key, and an EntityReference for the related Customer

Entity Framework will keep all three of these in sync. If you change the customer by setting the navigation property \\[myOrder.Customer=myCustomer\\], the CustomerID and the CustomerReference.EntityKey will automatically be updated. Whichever of the three you change, the others will sync up. However, the beauty is that you need not have the reference object available. If you set the foreign key \\[myOrder.CustomerID=24\\], and there is no instantiated object for that customer, the CustomerReference.EntityKey will still be updated and EF will have all the information it needs to update the database.

Foreign Keys in ASP.NET Development
One of the places where the lack of foreign keys was especially painful was in ASP.NET applications. For example, data binding controls that work with DataSource controls (e.g., ObjectDataSource) are able to update scalar properties but cannot automatically update navigation properties. In web applications, we were forced to write extra code to track the original and new relationships to send any changes made in the UI back to the data store. In the first edition of my book, Programming Entity Framework (O'Reilly Media), it was frustrating to have to dedicate extra pages to explaining and bridging this gap.

Now, the data source controls can work directly with the foreign key properties in data-binding scenarios and automatically persist changes back to your objects or the data store. The extra effort is no longer necessary. There are many more benefits to having direct access to the foreign keys, but there are also other Beta 2 additions to look at!

Additional Stored Procedure Support
If you read "Renovations to .NET 4.0's Entity Framework," you've seen the important improvement to stored procedure support that lets you map to procedures that return random results. In EF 1.0, when the shape of the results didn't line up (exactly) with a particular entity in the model or a scalar, you had to go to great lengths to use them in your model. This was a show-stopper for many developers looking at EF. In Beta 1, it became possible to map these "randomly shaped" results back to Complex Types. But there was still something lacking. The design tool required that you manually define each complex type that you wanted to capture the results of a function call.

I'm very happy to see that in Beta 2, the Import Function wizard can not only discover the schema of the data returned by a stored procedure but can create a complex type for you from that schema. Figure 7 shows the new Function Import wizard with the additional features.

Clicking the Get Column Information button executed the stored procedures in the database, examined the results, and displayed the schema of those results in the table below the button. Once I did this, the Create New Complex Type button was enabled. The effect of that button is that a new complex type is created (which you can see in the model browser), and it is automatically selected as the value for the Complex type to return (SalesbyYearMinimum_Result).

The ability to map a stored procedure to a complex type and the fact that the creation of the type is now automated is a far cry from the minimal support in EF 1.0. I think that many developers who turned away from EF because they had so many stored procedures they wanted to use will be very happy to see this change.

One-Way Relationships
When you or the designer creates an association between two entities in a model, the designer will automatically create navigation properties for both sides of the relationship. Figure 8 shows the Address and SalesOrderHeader entities that have a relationship.

Figure 8: Two-way navigation

It's logical to navigate from the order to its address. But it may not make as much sense to begin with an address and see what orders were shipped there. In EF 1.0, it was possible to remove a navigation property, but you had to do it in the XML. There was no designer support. Now, whether or not you're using foreign keys in your model, you can simply delete the undesired navigation property from the entity. The association between the entities and the other navigation property will remain intact, as Figure 9 shows.

Figure 9: One-way navigation
 
New Features of EntityDataSource
The EntityDataSource is an ASP.NET DataSource control that was part of the first version of EF. It now supports a new ASP.NET feature called QueryExtender as well as the new Plain Old CLR Object, or POCO (simple class), support that Entity Framework gained.

The new QueryExtender control allows you to declaratively add querying to DataSource controls on your web page, as Figure 10 shows.

On an .aspx page, the QueryExtender acts as a bridge between the TextBox control and the EntityDataSource control. The source of the QueryExtender defines a SearchExpression (Where LastName Contains) to be applied to the TargetControl (EntityDataSource1) and uses the text value of the ControlParameter (txtSearch)  as the value to search for.


    
    
    
  

SearchExpression is just one of the types of queries you can create in a QueryExtender.

Using a QueryExtender, you aren't required to add code to execute the query and repopulate the grid. This is a great tool for rapid application development (RAD) websites, and since EntityDataSource is a first-class ASP.NET DataSource, it, too, can benefit from this control.

Because the EntityDataSource uses the generated classes as its basis, using POCO classes that map back to your model is a natural extension to the control's capabilities. You can read more about the new POCO support in "Renovations to .NET 4.0's Entity Framework."

Lazy Loading Changes
Beta 1 brought us the Entity Framework's new lazy loading capabilities to automatically retrieve related entities without having to explicitly call the Load method. There are two changes from Beta 1. The first, a minor change, is that the property name was changed from DeferredLoadingEnabled to LazyLoadingEnabled. The second, a major change, is that with any new model you create, lazy loading is enabled by default. This is only for new models, so that you won't get unexpected behavior of applications with models that you upgrade to VS 2010.

The way this works is that the EDM Wizard inserts a special attribute in the CSDL's EntityContainer element.

Annotations in the model are there for the code generator to read. When the default code generator creates classes from the model, it sees this attribute and inserts "ContextOptions.LazyLoadingEnabled=true" into each of the EntityContainer constructors. Therefore, when you instantiate a new context in your code, it will automatically use lazy loading.

If you're bringing models from VS 2008 or VS 2010 Beta 1 into the new beta and would like lazy loading enabled by default, just add the annotation:LazyLoadingEnabled attribute into the CSDL's EntityContainer.

Query Improvements
Much work has been done to improve how queries are generated, so that they're more efficient and provide better performance. In addition, there are some new query operators for LINQ to Entities and Entity SQL.

One of the highlights for me is the use of the LIKE operator in generated queries. For example, the query

from c in context.Customers where c.LastName.StartsWith("S") select c

resulted in an ugly query that couldn't leverage default indexing in SQL Server. Here is the predicate of the T-SQL generated by version 1:

WHERE (CAST(CHARINDEX(N'S', \\[Extent1\\].\\[LastName\\]) AS int)) = 1

Now, the generated query uses the very efficient LIKE operator:

WHERE \\[Extent1\\].\\[LastName\\] LIKE N'S%'

There's also a new LINQ method that many people will be happy to see: Contains.

from p in context.Products where p.Name.Contains("Helmet") select p

Contains also triggers the use of the LIKE operator. Here's the T-SQL predicate for the previous query.

WHERE \\[Extent1\\].\\[Name\\] LIKE N'%Helmet%'

There are a many more improvements to be aware of. In an ADO.NET team blog post, Kati Iceva lists the details of the many improvements in marvelous detail. We weren't able to witness them in Beta 1, but you can now experience the fixes in Beta 2.

The ObjectMaterialized Event
One of the complaints about EF 1.0 was that there were not a lot of points of extensibility. An interesting addition to the ObjectContext is the new ObjectMaterialized event. When you query data and that data is returned, the ObjectContext instantiates new objects and populates them with the incoming data. This is referred to as object materialization.

This new event fires just after the scalar properties of each new object have been filled, but before the navigations have been dealt with. You can use ObjectMaterialized to apply a common bit of logic any time objects are created as a result of a query. This doesn't let you override the object materialization, but you can enhance it.

One experiment I've done with this event in the new edition of my book, Programming Entity Framework, is to check for the type being populated. If it were a VacationDestination type, I called a method in the VacationDestination class that gets real-time weather data from the Internet for the destination, then populates a custom property that I could access in my application. Here's the event-handler code:

void MyEntities_ObjectMaterialized(object sender, ObjectMaterializedEventArgs args)
\\{
  if (args.Entity is Lodging)
  \\{
    VacationDestination dest = (VacationDestination)args.Entity;
    dest.Materialized();
  \\}
\\}

But Wait, There's More!
There are still a number of new features in Beta 2 that will speak to particular development scenarios, such as the capability of using binary data for EntityKeys and foreign keys, improvements to database generation provided through Model-First development, and more. The Entity Framework team lists an overview of the new features on their team blog (blogs.msdn.com/adonet) in a post dated October 19, 2009.

If you haven't read "Renovations to .NET 4.0's Entity Framework," which covers important changes to the designer, support for agile development and more, I recommend that you check it out. The new EF is vastly improved for building real enterprise applications. If you haven't considered EF for your .NET applications, it's definitely time to take a closer look.

Julia Lerman is a Microsoft MVP, .NET mentor, and consultant. Julie presents on data access and other topics at user groups and conferences around the world, blogs at thedatafarm.com/blog, and is the author of Programming Entity Framework (O’Reilly Media) and the upcoming second edition. Follow Julie on Twitter at julielermanvt.

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish