Office Test - Tutorial 14

The 14th page of the OfficeTest General Tests tutorial looks again at using ObjectDataSource and custom made business objects. This time we'll look at one method of using sub-class properties to handle foreign key relationships. If you want to review the other tutorials, the central page can be found here Firebird and .NET 2.0 development Example.

14. ObjectDataSource, Project 2

    This tutorial is really just an extension of the last one. It uses the same classes and almost the same webpage. The only real difference is a couple of methods one the data class and binding settings on the webpage..

    Project 2: BLL - Business Logic Layer.
    Lets start by taking a look at what we are using that is different in the ProjectData class.

    ProjectData

    public class ProjectData
    {

    ...

      public int ManagerID {
        get {
          return Manager.EmployeeID;
        }
        set {
          if (value == -1) {
            manager = new EmployeeData();
          }else {
            List<EmployeeData> managers = EmployeeList.LoadRecord(value);
            manager = managers[0];
          }
        }
      }

      public string ManagerName {
        get {
          return manager.FirstName + " " + manager.LastName;
        }
      }

    ...

    }
       

    Two new public properties ManagerID and ManagerName have been added to ProjectData. Manager name is a simple readonly property than returns the employees name in a format fit for our display. We don't absolutely need this but it allows us to show the name in a format usefull for our current needs rather than forcing the EmployeeData class to know how we want to use it.

    More important is the ManagerID. This property has a more complex set construct. When the ManagerID is set to an EmployeeID it uswa the static LoadRecord method from EmployeeList to load the data for that EmployeeID automatically. This saves us having to write code outside the class to handle this. It essentially makes maintaining the manager class property mostly transparent to outside code. I say mostly because we still need an EmployeeID property which is separate from our Manager property.

    ProjectList
    ProjectList is exactly the same for this tutorial as the last so we don't really need to look at this code. However I threw in one additional method that is unrelated but handy for other purposes.

    [DataObjectMethod(DataObjectMethodType.Select)]
    public static List<ProjectData> LoadRecord(OrderedDictionary keyValues) {
      int projectID = (int)keyValues["ProjectID"];
      return LoadRecord(projectID);
    }
       

    This new LoadRecord routine uses the DataKeyNames property from a GridView or DetailsView as a parameter instead of int ProjectID. This is usefull when you want to develop a more generic base List class that supports multi-column primary keys. In this simple example I just extract the ProjectId from the OrderedDictionary and call the existing LoadRecord(int ProjectID). You need to pass GridView.SelectedDataKey.Values which contains the values for the current row related to the columns listed in DataKeyNames.

    WebPage Markup properties
    We'll take a look at ObjectDataSource odsCurrentProject and the DetailsView since these are the only objects that really changed for this tutorial.

    ObjectDataSource

          <asp:ObjectDataSource ID="odsCurrentProject" runat="server" DataObjectTypeName="ProjectData"
            DeleteMethod="Delete" InsertMethod="Insert" OldValuesParameterFormatString="original_{0}"
            OnDeleted="odsCurrentProject_Deleted" OnInserted="odsCurrentProject_Inserted" OnUpdated="odsCurrentProject_Updated"
            SelectMethod="LoadRecord" TypeName="ProjectList" UpdateMethod="Update">
            <SelectParameters>
              <asp:ControlParameter ControlID="gvProjects" Name="keyValues" PropertyName="SelectedDataKey.Values"
                Type="Object" />
            </SelectParameters>
          </asp:ObjectDataSource>
       

    I've shown the code for odsCurrentProject just so you can see where the definition for SelectedDataKey.Values is assigned. The select method is still LoadRecord but only one LoadRecord accepts an OrderedDictionary as a parameter so the correct one will be called.

    DetailsView

    <asp:TemplateField HeaderText="Manager" SortExpression="Manager">
      <EditItemTemplate>
        <asp:DropDownList ID="DropDownList1" runat="server" AppendDataBoundItems="True" DataSourceID="odsEmployees"
          DataTextField="FirstName" DataValueField="EmployeeID" SelectedValue='<%# Bind("ManagerID") %>'>
          <asp:ListItem Selected="True" Value="-1">Null</asp:ListItem>
        </asp:DropDownList>
      </EditItemTemplate>
      <InsertItemTemplate>
        <asp:DropDownList ID="DropDownList2" runat="server" AppendDataBoundItems="True" DataSourceID="odsEmployees"
          DataTextField="FirstName" DataValueField="EmployeeID" SelectedValue='<%# Bind("ManagerID") %>'>
          <asp:ListItem Selected="True" Value="">Null</asp:ListItem>
        </asp:DropDownList>
      </InsertItemTemplate>
      <ItemTemplate>
        <asp:Label ID="Label1" runat="server" Text='<%# Bind("ManagerName") %>'></asp:Label>
      </ItemTemplate>
    </asp:TemplateField>
       

    We are looking at just the Manager template field for the DetailsView here. As you can see the template field is simpler than the last tutorial. The new ManagerID property gives us something even simpler to bind to. The ItemTemplate uses the ManagerName for display but both edit templates use ManagerID. When a new employee is selected and the ManagerID is assigned the SET method in the property will automatically fill out the rest of the EmployeeData class represented by the Manager property.

    If you look at the partial class code for the WebPage you'll notice that mess of code required in the last tutorial is now gone. Only the code for keeping our DetailsView in sync with the GridView is required.

    Conclusions
    Sometimes adding a little extra code into the base business logic layer can remove a lot of complexity in other areas. The current code used to fill out the Manager class should really be modified to use an EmployeeList already populated and stored in a global cache somewhere. This would reduce calls to the database and improve overall performance. Changes like this are simple to make under the current design of the class.

This is the last tutorial in this series. I hope it has been helpfull in getting you started with building basic ASP.NET 2.0 WebSites using Firebird or any other database.