Tuesday, December 7, 2010

Entity Framework Pattern

In ASP.NET, we use the Entity Framework (EF) to connect to do all data manipulation. Through much trial and error, we've settled on the following pattern for implementing a successful EF project.

First, create a project where the EF's EDMX file will reside. We'll call this project MLS.SampleEF.Data.

Add a new item to that project called ADO.NET Entity Data model. Call it DataModel.edmx. Once you have gone through the wizard and created an edmx file based on your database schema, add a new class to the project called Context.cs. Add the following to it:


public static DataModelEntities getContext() {
return new DataModelEntities();
}


This class will be used in every EF query. You can modify it to provide a specific connection string if desired. Otherwise, it uses what's stored in the .config file of your executing assembly.

We have another project that works as the "business" layer. In this example, it'll be called MLS.Sample.Business. In this project we create classes that will be our business object representation of the data.

For example, assuming we have a Customer table. We create a CustomerBO class which will contain properties that our GUI will access and use:


public class CustomerBO {
public int customerId {get; set;}
public string firstName {get; set;}
public string lastName {get; set;}
public string fullName {
get {
return string.Format("{0}, {1}", lastName, firstName); }
}
}
}


In each of our business classes, we have a "wrapper" which takes an IQueryable object (which comes from the EF), and maps it over to the business object. For example, assume we have this static method which retrieves a customer list and returns a List<CustomerBO>. In the sample below, the datamodel contains the definition for the Customer class, while CustomerBO is our business object that will be returned to the GUI.


public static List<CustomerBO> getCustomers() {
using (var context = Context.getContext()) {
var lst = from c in context.Customers
select c;

// Wrap the EF results to a List<Customer>
return toCustomerList(lst);

}
}

/// Wraps a queryable object to a List<Customer>
private static List<CustomerBO> toCustomerList(IQueryable<Customer> queryCustomerData) {
var data = from c in queryCustomerData
select new CustomerBO() {
customerId = c.customerId,
firstName = c.firstName,
lastName = c.lastName
};

return data.ToList();
}


A few notes about the toCustomerList method. Recall that EF queries don't actually hit the database when they are "created" - instead, the actual query occurs at the time the data is accessed. In our sample above, the database isn't queried until the return data.ToList() line in the toCustomerList method.

We also make sure that every method which returns data to the GUI goes through the toCustomerList method. It ensures us that the CustomerBO object will always be populated with the same data regardless of the EF query used to create the data. It also lets us populate BO object properties that wouldn't normally be selected in a query. For example, let's say we added an OrderCount property to our bo and wanted to make sure that it was always populated for the GUI, we could change the toCustomerList method to do this:


public int orderCount {get; set;}

/// Wraps a queryable object to a List<Customer>
private static List<CustomerBO> toCustomerList(IQueryable<Customer> queryCustomerData) {
var data = from c in queryCustomerData
select new CustomerBO() {
customerId = c.customerId,
firstName = c.firstName,
lastName = c.lastName,
orderCount = c.CustomerOrders.Count()
};

return data.ToList();
}


Now if we add a new method to retrieve a single customer and wrap it using our toCustomerList method, we don't have to make sure to explicitely set the orderCount in our getCustomer method because it will be handled for us in the "wrapper":


public static CustomerBO getCustomer(int customerId) {
using (var context = Context.getContext()) {
var lst = from c in context.Customers
where c.customerId == customerId
select c;

// Wrap the EF results to a List<Customer> and return the first item (be sure to check for nulls!)
return toCustomerList(lst)[0];
}

}

Wednesday, March 31, 2010

Using jQuery's Dialog in Conjuction with .Net Postbacks

In a recent Asp.Net/C# project I needed to figure out a way to use a jQuery dialog box along with the built-in jQuery buttons and still do a button postback to my asp.net page. This post explains how I went about accomplishing this.

First, on my form I created my <div> which would be used as my jQuery dialog box.


<div id="dialog" style="display:none" title="Test Dialog">
This is my test dialog.
</div>


Then on my form, I created the button which I wanted to use to catch the onClick event. Keep in mind, this button won't actually do anything except provide the onClick event, we'll actually make it invisible to the user by setting display:none in the style:


<asp:button style="display:none" runat="server" id="btnPost" text="" onclick="btnPost_click">
</asp:button>


Finally, here's the javaScript jQuery code that will run the dialog box:



<script>

$(document).ready(function() {
$('#dialog').dialog({
modal: true,
autoOpen: false
buttons: {
"Cancel" : function () {
$(this).dialog("close");
},
"OK" : function () {
<asp:literal id="litBtnPost" runat="server">
}
}
});
});

</script>


Notice in here is a asp:Literal control. This control will actually contain a bit of javaScript that will call the postback as if it were clicked from the actual asp:button itself. To set it, in the page_load of your code behind, do this:


litBtnPost.Text = string.Format("{0};", Page.ClientScript.GetPostBackEventReference(btnPost, string.Empty));


So now all you need is a way to trigger the dialog box:


<a href="javascript: void(0);" onclick="$('#dialog').dialog('open');">Show Dialog</a>


When the OK button is clicked, a .net postback will occur on your page and will be handled by the btnPost_click event.