programming4us
programming4us
WEBSITE

Advanced ASP.NET : The Entity Framework (part 3) - Handling Errors & Navigating Relationships

6/23/2011 4:23:43 PM

5. Querying the Data Model

Now that you've taken a tour of the data model code, you're ready to use it in your application. In fact, it's remarkably easy.

Consider the simple data-bound grid of products shown in Figure 7. To create this page, you simply need to instantiate the NorthwindEntities class (from the NorthwindModel namespace), retrieve the collection or Product objects from Products property, and call DataBind():

Dim entities As New NorthwindEntities()
GridView1.DataSource = entities.Products
GridView1.DataBind()

Figure 7. Products retrieved through a data model

The NorthwindEntities class, like all context classes, has three constructors. If you use the no-argument constructor (as in this example), it uses the connection string that's defined in the web.config file. Alternatively, you can use a constructor that allows you to supply the connection string as a string or EntityConnection object.

6. Handling Errors

Whenever you access a database, you need to use the proper error handling code, and the Entity Framework is no exception. However, the Entity Framework can easily mislead developers into placing their exception handling code in the wrong place.

As you know, the risky part of data access is the connected operations you perform—for example, opening a connection and executing SQL commands. Your attempt to contact the database or communicate it with can fail for a variety of reasons. The database server could be offline, the database server could be swamped by too many simultaneous connections, the table you want to use might not exist, and so on. Based on these considerations, you probably expect to place your exception handling code around the code that reads the Products collection. In the previous example, that means this statement here:

Dim entities As New NorthwindEntities()
GridView1.DataSource = entities.Products
GridView1.DataBind()

This seems reasonable, but it isn't correct. Although this line of code appears to access the Products collection, it actually retrieves something different—a special iterator object that's able to get the data you need as soon as you attempt to use it. This sleight of hand is part of LINQ's deferred execution feature, which you learned about earlier.

Usually, database operations with the Entity Framework happen later than you expect. They don't happen when you create the context object or access its properties. Instead, they occur when you iterate over a collection of entities or when you access a single entity object. In the previous example, the database work actually takes place when you call GridView1.DataBind(), because this tells the GridView to iterate over the Products collection and then triggers the Entity Framework to fetch your data.

Thus, the correct error handling solution looks like this:

Dim entities As New NorthwindEntities()
GridView1.DataSource = entities.Products
Try
GridView1.DataBind()
Catch err As Exception
' (Do something here, like displaying an error message.)
...
End Try

NOTE

As you'll see a bit later, you can force the Entity Framework to load your data earlier. However, doing so may compromise the performance or the flexibility of your code. Most of the time, you'll stick with deferred execution, despite the potential confusion it causes.

Unfortunately, error handling in an application that uses the Entity Framework is not always this straightforward. In more complex examples, database operations might take place in several places. For example, in the following section you'll see how you can use relationships to show related information from different tables. When taking this approach, a database operation occurs whenever you begin iterating over a new collection of records with a For Each block.

So, what's the solution? One approach is to use the ToList() method, which converts any entity collection into an ordinary in-memory collection, triggering the database query in the process:

Dim entities As New NorthwindEntities()
GridView1.DataSource = entities.Products.ToList()
GridView1.DataBind()

Although this makes the data access operations more predictable, it's a dangerous practice. Deferred execution allows LINQ and the Entity Framework to optimize database queries. If you get into the habit of calling ToList(), you effectively circumvent this mechanism, which can harm the performance of your application.

If you don't want to worry about the precise code location where an exception might occur, you can use a better solution—just wrap everything in a giant exception handling block that catches database-specific exceptions. The most straightforward way to do this is to move your data access code to another method. Then you can wrap your method call in an exception block, like this:

Try
' Call the method that does all the data processing and display.
DataBindProductGrid()
Catch err As SqlException
...
End Try

7. Navigating Relationships

The Entity Framework has a particularly elegant way of dealing with relationships. Rather than forcing you to use specific methods or separate queries, you can simply move from one record to its related data using the navigation properties that are defined in the data model.

It all starts with the entity model diagram. There, you'll see dotted lines that indicate each relationship. For example, consider the portion of the diagram shown in Figure 8.

Figure 8. Relationships between the Customer, Order, Order_Detail, and Product entities

The 0..1, 1, and * characters at either end of the dotted line give you additional information about the relationship.

For example, a relationship line that goes from 1 to * (like the one between the Order and Order_Detail entities) indicates a one-to-many relationship. Each parent record in the first table (Order), where the 1 is shown, has one or more matches in the child table (Order_Detail), where the * is shown. (To actually figure out what fields are involved in a given relationship, you need to double-click the relationship line.)

A relationship line that goes from 0..1 to * indicates a one-to-many relationship that allows null values. In other words, the 0 represents that there may be no match. For example, in the data model shown in Figure 8, the Order.CustomerID property can be null. That means that for each Order record, there may be one matching Customer entity or none.

MANY-TO-MANY RELATIONSHIPS

A relationship line that goes from * to * indicates a many-to-many relationship that's connected with the help of a junction table. For example, in the Northwind database every Customer record can have one or more associated CustomerDemographic records, and every CustomerDemographic record can have one or more associated Customer records. To implement this design, the database uses a junction table named CustomerCustomerDemo. Essentially, each record in CustomerCustomerDemo is a pairing that links one record in Customers to one record in CustomerDemographics. (In fact, the CustomerCustomerDemo has just two fields: CustomerID, which points to the Customers table, and CustomerTypeID, which points to the CustomerDemographics table.)

This setup may seem a bit awkward, but it's a standard part of database diagram. The neat part is that the Entity Framework is intelligent enough to pick up on this sort of association. Instead of translating the table model to your entity classes exactly (and creating a Customer, CustomerDemographic, and CustomerCustomerDemo entity), the Entity Framework generates just the Customer and CustomerDemographic entities. It links them together using the power of collections, giving you a more natural object model to work with.

And best of all, the Entity Framework manages the CustomerCustomerDemo table behind the scenes. For example, if you add a new related CustomerDemographic for an existing Customer , the Entity Framework automatically creates the CustomerCustomerDemo record that connects them.


The relationships that appear in your entity model diagram are also represented through navigation properties. For example, if you look at the bottom of the Order box in Figure 24-10, you'll see four navigation properties. The Customer, Employee, and Shipper properties return a linked parent record (or null (Nothing) if none exists). In other words, Order.Customer returns the Customer who placed the order. The Order_Details property returns a collection of linked child records (as indicated by the plural property name). In other words, Order.Order_Details provides a collection of all the order items in a given order, as Order_Detail objects.

Here's an example that uses these navigation properties to display some information in a page, with no data binding. It begins by retrieving a list of customers and then retrieves some information about the orders made by each customer:

Dim entities As New NorthwindEntities()

' Build a string full of HTML markup.
Dim sb As New StringBuilder()
For Each customer As Customer In entities.Customers
' Write out the customer information in bold.
sb.Append("<b>")

sb.Append(customer.CompanyName)
sb.Append("</b><br />")

' List this customer's orders.
For Each order As Order In customer.Orders
sb.Append(order.OrderID.ToString())
sb.Append(" - made on date: ")
sb.Append(order.OrderDate.Value.ToShortDateString())
sb.Append("<br />")
Next
' Add a horizontal line.
sb.Append("<hr /><br />")
Next

' Show the HTML in a Label control.
lblData.Text = sb.ToString()

Figure 9 shows the result.

Figure 9. Navigating a relationship

Writing exception handling logic for this sort of code can be tricky. The database operations occur whenever you start a For Each block (either to process the list of customers or to look at the orders for a given customer). To prevent your code from descending into a tangle of spaghetti-style exception handlers, it's best to put all this logic in a dedicated method and wrap your method call in an exception handling block, as described in the previous section.

Other  
 
PS4 game trailer XBox One game trailer
WiiU game trailer 3ds game trailer
Top 10 Video Game
-   Uncharted 4: A Thief's End | E3 2015 Extended Gameplay Trailer
-   V.Next [PC] Kickstarter Trailer
-   Renowned Explorers [PC] Launch Date Trailer
-   The Void (Game Trailer)
-   World of Warships [PC] Open Beta Trailer
-   F1 2015 | Features Trailer
-   Battle Fantasia Revised Edition | Debut Trailer for Steam
-   Victor Vran [PC] Story Trailer
-   Star Wars Battlefront PC Alpha footage
-   Skyforge [PC] Open Beta Gameplay Trailer
-   Armored Warfare [PC] PvE Trailer
-   F1 2015 [PS4/XOne/PC] Features Trailer
-   Act of Aggression [PC] Pre-Order Trailer
-   Sword Coast Legends [PC] Campaign Creation E3 2015 Trailer
-   Sword Coast Legends [PC] Campaign Creation E3 2015 Dungeon Run Trailer
Game of War | Kate Upton Commercial
programming4us
 
 
programming4us