Using Dynamic Views In ASP.NET MVC 2

A really cool addition to ASP.NET MVC 2 is the ability to use the dynamic type as the object passed into the view. This is also known as a dynamic view. If you create a new view and don’t create a strongly typed view, out of the box, the MVC framework will make the view inherit from the ViewPage class, but the generic type will be dynamic, like this:

<%@Page Language=”C#” MasterPageFile=”~/Views/Shared/ViewMasterPage.Master” Inherits=”System.Web.Mvc.ViewPage”
<dynamic>”%>

Using the dynamic type is good because it allows you to create your objects on the fly. The downside of this is because the view is not strongly typed, you don’t get the compile time checking. For me compile time checking is a compelling reason to use strongly typed views.
In this example, I’m going to pass a collection of time zones into the view as a dynamic object to the view. To see this in action, I’m going to create a small ASP.NET MVC 2 website. If you haven’t got Microsoft Visual Studio 2010, you can download the Express edition here.
To begin, let’s add the view straight away. Normally you would do this after you have defined your action, but that’s not the focus of this article. By adding a view that is not strongly, we get to use the dynamic type. Here’s the view:
AddView
The HTML that’s added inherits from the ViewPage class, but the generic type is dynamic:
<%@Page Title=”” Language=”C#” MasterPageFile=”~/Views/Shared/ViewMasterPage.Master” Inherits=”System.Web.Mvc.ViewPage”
<dynamic>”%>
Cool huh?! Now I can add a dynamic object. I’m going to be displaying the list of time zones on your computer in a drop down list. Here’s the code:
<asp:ContentID=”Content2″ ContentPlaceHolderID=”MainContent” runat=”server”>
<%:Html.DropDownList(“DisplayName”,(IEnumerable=””
<SelectListItem> )Model.TimeZones) %>
</asp:Content>
I can access the dynamic type via the Model property which is available to the view by default. If you compiled this now, even though I haven’t created a real object, it will still compile.
Ok let’s add code to the controller to return the list of time zones. I’m adding this to the HomeController. Here’s the code below:
C#

public ActionResult GetTimeZones()
{
dynamic viewData = new ExpandoObject();
viewData.TimeZones = from p in TimeZoneInfo.GetSystemTimeZones()
select new SelectListItem
{
Text = p.DisplayName,
Value = p.Id
};
return View(“Index”, viewData);
VB.NET

Public Function GetTimeZones() As ActionResult
Dim viewData As Object = New ExpandoObject()
viewData.TimeZones = From p In TimeZoneInfo.GetSystemTimeZones()

Anúncios

ADO.NET Entity Framework 4.0 : Loading Data in 4 ways

We are working with Relational Database and using ADO.NET Entity Framework 4.0, it is inevitable that we need to load data. EF4 has improved Lazy Loading feature as compared to its previous version. We can also combine both Lazy and Eager loading.

Based on the amount of data we bring in and type of application we develop, we need to decide which one to choose. There is no single solution.

I have used two tables from Northwind database – Customer and Order (1 to many).

Now, each Customer will have n number of orders, so ideal for Lazy or Immediate loading.

Where is the catch?

This uses a feature introduced in ADO.NET 2.0 known as MultipleActiveResultSets (MARS). This gets added to the connection string of EF4.

Scenario 1: When Lazy loading is enabled (default)

By default in EF4 Lazy Loading is enabled through the Model designer. Which means if you write the below code, to get for every Order, it would send a SQL statement to the SQL Server.

using (var ctx = new NorthwindEntities())

{

    var q = from c in ctx.Customers

            select c;

    foreach (var cust in q)

    {

        Console.WriteLine(“Customer : {0}”, cust.CompanyName);

        Console.WriteLine(“Respective Orders…”);

        foreach (var ord in cust.Orders)

        {

            Console.WriteLine(“Order given on {0}”, ord.OrderDate);

        }

        Console.WriteLine();

        Console.ReadKey();

    }

}

In the background for the first foreach loop it would execute the query in SQL Server to fetch the data from only Customers table. Then for the inner foreach loop it would run individual query to get respective set of orders for each customer. So if there are 100 customers and 1000 orders, the total number of queries would be 1001.

Pros and Cons

This is acceptable in situations like where you have paged navigation and only when user asks for it, you load it, else leave it. This involves multiple round trips.

But when you want to pass data thorough layers, you would not be using it as because there will be no active open context. So when it would try to navigate to the child information no data will be found.

Scenario 2: Explicit Loading or conditional Lazy Loading

If you want to control the lazy loading on your own by loading the data only if logic requires, you should be disabling the Lazy Loading option and explicitly call it.

In the code, you need to add the line ctx.ContextOptions.LazyLoadingEnabled = false; This will switch off the Lazy Loading.  

//Lazy loading OFF

ctx.ContextOptions.LazyLoadingEnabled = false;

var q = from c in ctx.Customers

        select c;

foreach (var cust in q)

{

    Console.WriteLine(“Customer : {0}”, cust.CompanyName);

    Console.WriteLine(“Respective Orders…”);

    //Conditionally Load the child information

    if (1 == 1)

        cust.Orders.Load();

    foreach (var ord in cust.Orders)

    {

        Console.WriteLine(“Order given on {0}”, ord.OrderDate);

    }

    Console.WriteLine();

    Console.ReadKey();

}

Pros and Cons

This helps us to control the number of roundtrips based on application need. However, we need to be extra careful about testing our code before final deployment.

 

Scenario 3: When Eager Loading is enabled

If we switch off the Lazy Loading as discussed in Scenario 2 and want all the records to be available in the memory, then we need to use .Include(Entity).

//Lazy loading OFF

ctx.ContextOptions.LazyLoadingEnabled = false;

var q = from c in ctx.Customers.Include(“Orders”)

        select c;

foreach (var cust in q)

{

    Console.WriteLine(“Customer : {0}”, cust.CompanyName);

    Console.WriteLine(“Respective Orders…”);

    foreach (var ord in cust.Orders)

    {

        Console.WriteLine(“Order given on {0}”, ord.OrderDate);

    }

    Console.WriteLine();

    Console.ReadKey();

}

Pros and Cons

This brings all the Customer and Order information via a single query. This is required when we pass data from one layer to another layer. It also reduces the number of roundtrips. However, it can capture large about of your memory space.

If we check in the profiler we would see a single query like (removed few characters)

SELECT

[Project1].[C1] AS [C1],

[Project1].[CustomerID] AS [CustomerID],…

FROM ( SELECT

      [Extent1].[CustomerID] AS [CustomerID], …

      1 AS [C1],

      [Extent2].[OrderID] AS [OrderID], …

      CASE WHEN ([Extent2].[OrderID] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C2]

      FROM  [dbo].[Customers] AS [Extent1]

      LEFT OUTER JOIN [dbo].[Orders] AS [Extent2] ON [Extent1].[CustomerID] = [Extent2].[CustomerID]

)  AS [Project1]

ORDER BY [Project1].[CustomerID] ASC, [Project1].[C2] ASC

 

Scenario 4: Combination of Eager and Lazy Loading

We could also use .Include and enable lazy loading if we wish to load few data lazily and some one-shot. There is no harm doing it as we are taking the benefit of both the features.

MSDN References 

Loading Related Objects (Entity Framework)

http://msdn.microsoft.com/en-us/library/bb896272(VS.100).aspx