Joins and UI Binding with the Entity Framework

Introduction

Welcome, .NET Developers, to this installment of the .NET Nuts & Bolts column. In my last column, Introducing the Entity Framework, I covered introductory examples on the Entity Framework and compared LINQ to SQL. For this piece, I'll focus on building queries with the Entity Framework that involve multiple tables as well as binding in the UI with the EntityDataSource.

Queries with Joins

The Entity Framework is a new part of ADO.NET that allows you to build your applications against conceptual data models. It provides a greater level of abstraction and supports code that is independent of any particular relational database. It provides an Entity Data Model (EDM) for defining data at the database and conceptual level and mapping between the two. There are a nice set of tools that can be used to generate the Entity Data Model and corresponding objects from that represent the database. Part of that representation involves having a model of the relationships between entities. Figure 1 below depicts a snippet of an entity model and some of its relationships. Notice how the top half of an item such as Profile is made up of scalar properties. The bottom half of any given entity contains the associations/relationships with other entities.


Figure 1

The following example demonstrates the syntax involved in joining two entities together. Note the "equals" syntax used in the join statement. This syntax is different than comparison syntax in the query statement. Additionally, notice how the foreign key between the Review table and the Organization table is referenced for the Review. It is referenced through the Association name followed by any scalar properties. For example, my Review table has an in_OrganizationId that contains the reference. That table column is mapped to the actual in_id column in the Organization table through the association.

  using (Example_DataEntities dc = new Example_DataEntities())
{
var review = (from r in dc.Review
                    join o in dc.Organization on r.Organization.in_id equals 
  o.in_id
                    where r.in_Id == reviewId
                    select new
                    {
                    	o.vc_BusinessName,
                    	o.ch_ProviderNum
                    }).FirstOrDefault();

	// ...
}

It is also important with the entity model to understand how relationships are loaded. If we had selected the Review entity in the example above, that wouldn't guarantee the related Organization information were already loaded. The reference that exists on the Review is lazy loaded by default and you must ensure it is loaded before use.

  if (!review.OrganizationReference.IsLoaded)
{
review.OrganizationReference.Load();
}

It is important when deleting entities to ensure that its relationships are not loaded unless you are wanting to delete those records as well.

Stored Procedures

In working with LINQ and the Entity Framework, I've occasionally run in to situations where I can't quite figure out the correct query statement to retrieve the data I need. It's not that it can't be done, but more that I run out of time or budget to continue to try and figure out the correct statement. At times like that, I've found it helpful to be able to revert to building the SQL statement I need as a T-SQL stored procedure and then including the stored procedure in the entity model. You update your entity model to include the stored procedure. From there, you right click in the model designer and choose the option to add a function import. During the import process you choose the stored procedure, set the desired name, and determine if there is no return type, scalar return type, or an entity return type. Refer to Figure 2 below for an example of what the function import user interface looks like.


Figure 2

Once you have performed the function import, then you will find your new method available within the context of your entity model. You call the item just like any other method and pass in any of the defined parameters. The example below demonstrates making a call to a stored procedure that has been setup as a function import to retrieve data to display on a dashboard based on the current user and search criteria.

  using (Example_DataEntities dc = new Example_DataEntities())
{
this.gridViewReviews.DataSource = 
dc.GetReviewsForDashboard(Page.User.Identity.Name,
                this.txtSearch.Text);
this. gridViewReviews.DataBind();
}

Binding the UI with the EntityDataSource

The Entity Framework offers the EntityDataSource to use in binding the UI to your entity model. It implements an interface similar to other controls such as the LinqDataSource. You specify the context, entity set, and several other parameters that control the query.

Adjusting to EntityDataSource from the LinqDataSource

There is a primary difference between the EntityDataSource and the LinqDataSource, that is the ability to use the Selecting event to replace the results. With the LinqDataSource I've taken advantage of the Selecting event on a number of occasions such as with complex search forms where there are a number of criteria to factor in to the query and adjust. In the Selecting event I'd adapt and build the desired query to avoid getting hung up in a complexity of ControlParameters. The EntityDataSource does not support this same behavior. Instead, with the EntityDataSource you rely on the Select and Where or the CommandText properties to customize the query. The following example shows the use of the Select, Where, and WhereParameters to control the query. Note, you have the same kinds of options with the LinqDataSource, but I find it is more likely to need to depend on them with the EntityDataSource.

  <asp:EntityDataSource ID="ldsCompanies" runat="server" 
ContextTypeName="DataLayer.Example_DataEntities" 
EntitySetName="Organization" 
Select="it.[in_id], it.[vc_BusinessName], it.[ch_ProviderNum]"
OrderBy="it.[vc_BusinessName]"
Where="it.[in_tenantId] == @in_tenantId AND 
it.[vc_BusinessName] LIKE '%'+@OrganizationSearch+'%'">
<WhereParameters>
<asp:ControlParameter ControlID="txtOrganizationSearch" 
PropertyName="Text" Name="OrganizationSearch" DbType="String" 
ConvertEmptyStringToNull="false" />
      </WhereParameters>
</asp:EntityDataSource>

The following sample shows the use of the CommandText property to build a custom query. Note the use of the CommandParameters, which are similar to WhereParameters.

  <asp:EntityDataSource ID="edSettings" runat="server"                           ContextTypeName="DataLayer.Example_DataEntities"
OrderBy="it.[vc_Name]"
CommandText="SELECT atf.in_Tenant_Id, atf.in_Feature_Id, atf.bt_Enabled, 
atf.bt_Configurable, atf.bt_DefaultValue, af.vc_Name
FROM AppTenantFeatures AS atf
      	join AppFeatures AS af on atf.in_Feature_Id = af.in_Id 
      WHERE atf.in_Tenant_Id = @in_Tenant_Id
      ORDER BY af.vc_Name">
<CommandParameters>
      	<asp:ControlParameter ControlID="ddlTenants" Name="in_Tenant_Id" 
PropertyName="SelectedValue" Type="Int32" />
     	</CommandParameters>
</asp:EntityDataSource>

Summary

We covered examples of how to execute queries against the Entity Framework model that involve joining tables. We also explored how to use a stored procedure in the Entity Framework, which is certainly handy where there are complex queries you can't figure out quite how to build with a LINQ query. Additionally, we explored the EntityDataSource and some of the differences between that and the LinqDataSource. Hopefully each of these topics will help you through the learning curve as you further adopt the Entity Framework within your solutions.

Future Columns

The topic of the next column is yet to be determined. If you have something else in particular that you would like to see explained here you could reach me at mark.strawmyer@crowehorwath.com.



About the Author

Mark Strawmyer

Mark Strawmyer is a Senior Architect of .NET applications for large and mid-size organizations. He specializes in architecture, design and development of Microsoft-based solutions. Mark was honored to be named a Microsoft MVP for application development with C# for the fifth year in a row. You can reach Mark at mark.strawmyer@crowehorwath.com.

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Webinar Tuesday, August 26, 2014 1:00 PM EDT Customers are more empowered and connected than ever, and the customer's journey has grown more complex. Their expectations are growing and trust is diminishing as they may interact with multiple brands through web, mobile and social channels. Considering 70% of the buying process in a complex sale is already complete before prospects are willing to engage with a live salesperson -- it's critical to understand your customers and anticipate their needs.* …

  • Not long ago, security was viewed as one of the biggest obstacles to widespread adoption of cloud-based deployments for enterprise software solutions. However, the combination of advancing technology and an increasing variety of threats that companies must guard against is rapidly turning the tide. Cloud vendors typically offer a much higher level of data center and virtual system security than most organizations can or will build out on their own. Read this white paper to learn the five ways that cloud …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds