This example will show how NHibernate.Burrow and NHibernate.Burrow.AppBlock simplifies ASP.NET/NHibernate application development on a day-to-day basis. The full code is available in NHContrib/src/NHibernate.Burrow/examples/BasicThreeTier.
This simple example is about managing an entity called "Customer".
1: public class Customer
2: {
3: private string address;
4: private string companyName;
5: private string contactName;
6: private int id;
7: private bool isActivated;
8: private decimal salesPotential;
9:
10: private Customer(){}
11:
12: public Customer(string contactName)
13: {
14: ContactName = contactName;
15: }
16:
17: public int Id
18: {
19: get { return id; }
20: private set { id = value; }
21: }
22:
23: public string Address
24: {
25: get { return address; }
26: set { address = value; }
27: }
28:
29: public decimal SalesPotential
30: {
31: get { return salesPotential; }
32: set { salesPotential = value; }
33: }
34:
35: public bool IsActivated
36: {
37: get { return isActivated; }
38: set { isActivated = value; }
39: }
40:
41: public string CompanyName
42: {
43: get { return companyName; }
44: set { companyName = value; }
45: }
46:
47: public string ContactName
48: {
49: get { return contactName; }
50: set { contactName = value; }
51: }
52: }
The mapping file as follows
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="BasicThreeTier.Core.Domain.Customer, BasicThreeTier.Core"
table="Customers" lazy="false">
<id name="Id">
<generator class="identity" />
</id>
<property name="CompanyName" />
<property name="ContactName" />
<property name="Address" />
<property name="IsActivated" />
<property name="SalesPotential" />
</class>
</hibernate-mapping>
The first step will be creating a DAO for it. Here we create one by inheriting the DAO base from NHibernate.AppBlock
public class CustomerDAO : NHibernate.Burrow.AppBlock.DAOBases.GenericDAO<Customer>
{}
The DAO base class provides a lot of functions including CRUD and much more. But this inheritance is by no means mandatory. You can always use your own DAO.
Now the domain layer is ready. Let's create a page that lists all the all the customer entities in a grid view that is sortable and paged (both at DB side).
ListCustomer.aspx
<asp:GridView ID="grdCustomers" runat="server" AutoGenerateColumns="false" AllowPaging="True"
AllowSorting="True" PageSize="5" DataSourceID="odsAll">
<Columns>
<asp:TemplateField HeaderText="Customer ID" SortExpression="Id">
<ItemTemplate>
<asp:LinkButton ID="lbtSelect" OnCommand="lbt_SelectCommand"
CommandArgument='<%# Eval("Id") %>' runat="server"><%1: # Eval("Id") %></asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="CompanyName" HeaderText="Company Name" SortExpression="CompanyName" />
<asp:BoundField DataField="ContactName" HeaderText="Contact Name" SortExpression="ContactName" />
<asp:BoundField DataField="Address" HeaderText="Address" SortExpression="Address" />
<asp:BoundField DataField="SalesPotential" HeaderText="Sales Potential"
HtmlEncodeFormatString="true" DataFormatString="{0:C}" SortExpression="SalesPotential" />
<asp:BoundField DataField="IsActivated" HeaderText="Activated" SortExpression="IsActivated" />
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="odsAll" runat="server" TypeName="BasicThreeTier.Core.Dao.CustomerDAO"
EnablePaging="True" MaximumRowsParameterName="pageSize" StartRowIndexParameterName="startRow"
SortParameterName="sortExpression" SelectMethod="FindAll" SelectCountMethod="CountAll">
</asp:ObjectDataSource>
<uc1:EditCustomer ID="EditCustomer1" runat="server" Visible="false" OnUpdated="EditCustomer_Updated" />
The EditCustomer1 is a user control that we created to edit one customer, we'll talk about it later.
ListCustomer.aspx.cs
public partial class ListCustomers : System.Web.UI.Page
{
protected void lbt_SelectCommand(object sender, CommandEventArgs e) {
EditCustomer1.Bind(new CustomerDAO().Get(int.Parse(e.CommandArgument.ToString()))); protected void EditCustomer_Updated(object sender, EventArgs e) {
grdCustomers.DataBind();
}
}
The code behind may look like an excerpt, but it's not. It's just simple as that, we have a paged and sortable (both at Database side) gridview that lists all customers. The inherited DAO together with the ObjectDataSource take care of all the tedious work of the DB side sorting and paging. In the code behind, we only need two simple methods for binding the selected customer to the EditCustomer control and refresh the gridview when customer is modified in that control.
Now let's look at the EditCustomer user control.
EditCustomer.ascx
<h2>Edit Customer</h2>
Customer ID:<asp:Label ID="lblCustomerID" runat="server" /><br />
Company Name:<asp:TextBox ID="txtCompanyName" runat="server" /><br />
Contact Name:<asp:TextBox ID="txtContactName" runat="server" /><br />
Address:<asp:TextBox ID="txtAddress" runat="server" /><br />
Sales Potential:<asp:TextBox ID="txtSalesPotential" runat="server" /><br />
Activated:<asp:CheckBox ID="cbActivated" runat="server" /><br />
<ww:wwDataBinder ID="DataBinder" runat="server" DefaultBindingSource="customer">
<DataBindingItems>
<ww:wwDataBindingItem ID="dbiId" runat="server" BindingMode="oneway" ControlId="lblCustomerID"
BindingSourceMember="Id" />
<ww:wwDataBindingItem ID="dbiCompanyName" BindingSourceMember="CompanyName" ControlId="txtCompanyName"
runat="server" />
<ww:wwDataBindingItem ID="dbiContactName" BindingSourceMember="ContactName" ControlId="txtContactName"
runat="server" />
<ww:wwDataBindingItem ID="dbiAddress" BindingSourceMember="Address" ControlId="txtAddress"
runat="server" />
<ww:wwDataBindingItem ID="dbiSP" BindingSourceMember="SalesPotential" ControlId="txtSalesPotential"
DisplayFormat="{0:C}" runat="server" />
<ww:wwDataBindingItem ID="dbiIA" BindingSourceMember="IsActivated" ControlId="cbActivated"
BindingProperty="Checked" runat="server" />
</DataBindingItems>
</ww:wwDataBinder>
<asp:Button ID="btnUpdate" runat="server" OnClick="btnUpdate_OnClick" Text="Update" />
<asp:Button ID="btnCancel" runat="server" OnClick="btnCancel_OnClick" Text="Cancel" />
The wwDataBinder here is an optional 3rd party control that realizes Two-way databinding between UI controls and properties of the code behind class. This wonderful control is created by Rick Strahl. It eliminates the code that transfer values between form control values and entity properties. Detailed information about it can be found here. Again, this control is not mandatory by NHibernate.Burrow.
Now let's look at the code behind.
EditCustomer.aspx.cs
1: public partial class EditCustomer : UserControl {
2: public event EventHandler Updated;
3: [EntityField] protected Customer customer; public void Bind(Customer c) {
4: customer = c;
5: DataBinder.DataBind(this);
6: Visible = true;
7: } protected void btnUpdate_OnClick(object sender, EventArgs e) {
8: DataBinder.Unbind(this);
9: if (Updated != null)Updated(this, new EventArgs());
10: } protected void btnCancel_OnClick(object sender, EventArgs e) {
11: customer = null;
12: Visible = false;
13: }
14: }
Again, this is the complete code that is necessary to manage all the properties for the customer entity.
Now with the code listed here we created a three tier application that can list and manage all the customers in DB. As you can see here, the code is very straightforward and clean. No DB related management code anywhere, not even NHibernate is mentioned.
Conclusion
This example demonstrated that other than the advanced features, such as conversation, it provides, NHibernate.Burrow also greatly frees the developers from DB/NHibernate related concerns and thus enable them to focus mostly on project vised logic in their day-to-day development.