Blog: Posts from April, 2009

Labels
AJAX(112) App Studio(7) Apple(1) Application Builder(245) Application Factory(207) ASP.NET(95) ASP.NET 3.5(45) ASP.NET Code Generator(72) ASP.NET Membership(28) Azure(18) Barcode(2) Barcodes(3) BLOB(18) Business Rules(1) Business Rules/Logic(140) BYOD(13) Caching(2) Calendar(5) Charts(29) Cloud(14) Cloud On Time(2) Cloud On Time for Windows 7(2) Code Generator(54) Collaboration(11) command line(1) Conflict Detection(1) Content Management System(12) COT Tools for Excel(26) CRUD(1) Custom Actions(1) Data Aquarium Framework(122) Data Sheet(9) Data Sources(22) Database Lookups(50) Deployment(22) Designer(177) Device(1) DotNetNuke(12) EASE(20) Email(6) Features(101) Firebird(1) Form Builder(14) Globalization and Localization(6) How To(1) Hypermedia(2) Inline Editing(1) Installation(5) JavaScript(20) Kiosk(1) Low Code(3) Mac(1) Many-To-Many(4) Maps(6) Master/Detail(36) Microservices(4) Mobile(63) Mode Builder(3) Model Builder(3) MySQL(10) Native Apps(5) News(18) OAuth(9) OAuth Scopes(1) OAuth2(13) Offline(20) Offline Apps(4) Offline Sync(5) Oracle(11) PKCE(2) Postgre SQL(1) PostgreSQL(2) PWA(2) QR codes(2) Rapid Application Development(5) Reading Pane(2) Release Notes(183) Reports(48) REST(29) RESTful(29) RESTful Workshop(15) RFID tags(1) SaaS(7) Security(81) SharePoint(12) SPA(6) SQL Anywhere(3) SQL Server(26) SSO(1) Stored Procedure(4) Teamwork(15) Tips and Tricks(87) Tools for Excel(2) Touch UI(93) Transactions(5) Tutorials(183) Universal Windows Platform(3) User Interface(338) Video Tutorial(37) Web 2.0(100) Web App Generator(101) Web Application Generator(607) Web Form Builder(40) Web.Config(9) Workflow(28)
Archive
Blog
Posts from April, 2009
Saturday, April 11, 2009PrintSubscribe
Filtering And Business Rules

Data Aquarium Framework offers a unique approach to creating reusable business rules and logic for ASP.NET applications. Today we will explore filtering with business rules.

All code samples are built for a Data Aquarium application generated from Northwind database.

Task 1

You want to enhance the customer lookup capability of Northwind application to display only USA customers when users are editing orders in a grid view and have a UK customer list when users are editing orders in form view. This should not affect any other views that are presenting customers.

Solution

Create new class Class1 and add property Country as shown in example below.

C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using MyCompany.Data;

public class Class1 : BusinessRules
{
    public Class1()
    {
    }

    [RowFilter("Customers", "grid1", "Country")]
    public string Country
    {
        get
        {
            RowFilter.Canceled = String.IsNullOrEmpty(
                RowFilter.LookupContextController);
            if (RowFilter.LookupContextController == "Orders" && 
                    RowFilter.LookupContextView == "editForm1")
                return "UK";
            else
                return "USA";
        }
    }

}

VB

Imports Microsoft.VisualBasic
Imports MyCompany.Data

Public Class Class1
    Inherits BusinessRules

    <RowFilter("Customers", "grid1", "Country")> _
    Protected ReadOnly Property Country() As String
        Get
            RowFilter.Canceled = _
                String.IsNullOrEmpty(RowFilter.LookupContextController)
            If RowFilter.LookupContextController = "Orders" AndAlso _
                    RowFilter.LookupContextView = "editForm1" Then
                Return "UK"
            Else
                Return "USA"
            End If

        End Get
    End Property

End Class

This class is inherited from MyCompany.Data.BusinessRules base. 

Property Country is adorned with RowFilter attribute. This attribute will force the framework to evaluate the property whenever grid1 view of data controller Customers is expected to present data. The value of the property will be applied as a server-side filter.

The filtering property Country is notifying the framework that its value shall be ignored when property LookupContextController of RowFilter is null. This can be accomplished by assigning boolean value False to RowFilter.Canceled.

Row filter is constructed only once for each data page request received from the client. The framework will reset the cancellation flag of row filter prior to evaluating each business rules property matched to the requesting data controller view. If evaluation of the property has resulted in cancellation then property value is ignored. Otherwise the value is inserted as a parameterized SQL expression in the WHERE clause of SELECT statement constructed by the framework.

The third argument of RowFilter attribute  applied to Country property specifies the name of the field that must be filtered. This is useful if the property of the business rule is named differently than the actual field defined in the data controller view. It is redundant in our example.

Class BusinessRules features RowFilter property that gives you access to Controller, View, LookupContextController, LookupContextView, and LookupContextFieldName that are useful to determine if and how the filter shall be applied.  Lookup context properties are informing you if the data has been requested by the lookup field. You can examine lookup context field name to apply a server-side filter to the data that might be helpful if the same database lookup data is used to provide lookup values to more than one table in your database. If the data is requested by a standalone data view then you will find that all of the lookup context properties are equal to null.

Multiple RowFilter attributes can be applied to the same property.

Now you have to link the new business rules to Customers data controller defined in ~/Controllers/Customers.xml. This is done by adding attribute handler as shown here.

<dataController name="Customers" 
    conflictDetection="overwriteChanges" 
    label="Customers" xmlns="urn:schemas-codeontime-com:data-aquarium" 
    handler="Class1">
    ......

Run your application or navigate to the online demo at http://dev.codeontime.com/demo/filteringrules/?controller=Orders

Start editing any order in the grid view of orders.

image

Click on the link with the customer name.

image

Customer lookup window will display 13 records of customers from USA.

image

Press Escape key and click on any other link in Customer Company Name column. Click Edit button to start editing record in the form view editForm1.

image

Click on the lookup link in Customer Company Name field. Notice that only UK customers are presented.

image

Let’s see if our business rules have affected the global list of customers. Navigate to http://dev.codeontime.com/demo/filteringrules?controller=Customers. About ninety customer records shall be displayed. We have used RowFilter.Canceled property to prevent filtering when the data is no requested in the context of the lookup field.

image 

Task 2

You want to limit the list of employees to those born between 1/1/1950 and 11/1/1960.

Solution

Continue modifying our class and add BirthDate and BirthDate2 properties.

C#

[RowFilter("Employees", "grid1", "BirthDate", 
    RowFilterOperation.GreaterThanOrEqual)]
public DateTime BirthDate
{
    get
    {
        return new DateTime(1950, 1, 1);
    }
}

[RowFilter("Employees", "grid1", "BirthDate", 
    RowFilterOperation.LessThanOrEqual)]
public DateTime BirthDate2
{
    get
    {
        return new DateTime(1960, 1, 1);
    }
}

VB

<RowFilter("Employees", "grid1", "BirthDate", _
            RowFilterOperation.GreaterThanOrEqual)> _
            Protected ReadOnly Property BirthDate() As DateTime
     Get
         Return New DateTime(1950, 1, 1)
     End Get
End Property

<RowFilter("Employees", "grid1", "BirthDate", _
            RowFilterOperation.LessThanOrEqual)> _
           Protected ReadOnly Property BirthDate2() As DateTime
    Get
        Return New DateTime(1960, 1, 1)
    End Get
End Property

Link Class1 to ~/Controllers/Employees.xml data controller in the same fashion as we did for Customers data controller. Properties BirthDate and BirthDate2 are creating a range filter for employee field BirthDate.

You can see filtering by BirthDate in action at http://dev.codeontime.com/demo/filteringrules/?controller=Employees.

This filter is consistently applied whenever employee information is presented in data views.

Task 3

You want to filter data based on ASP.NET session variable.

Solution

Business rules have property Context that provide access to standard Request, Response, Session, Cache, and Application objects available in ASP.NET web forms. If you have a value stored in the session variable then you can easily apply its value as a filter.

<RowFilter("Customers", "grid1", "Country")> _
Protected ReadOnly Property CountryFilter() As String
    Get
        Return Context.Session("Country")
    End Get
End Property

Task 4

You want to filter data for a certain user roles.

Solution

The following code will inspect user role if a current user is not a member of Admin role then only customers from Finland are presented. Administrator’s view is not limited by a filter, which is accomplishing by cancelling filtering caused by CountryFilter property.

<RowFilter("Customers", "grid1", "Country")> _
Protected ReadOnly Property CountryFilter() As String
    Get
        If Context.User.IsInRole("Admin") Then
            RowFilter.Canceled = True
            Return String.Empty
        Else
            Return "Finland"
        End If
    End Get
End Property

Remember that if multiple filter properties are applicable to a give data page request then each filtering property must cancel row filter on its own.

Conclusion

Business rules in Data Aquarium Framework web applications allow efficient data filtering logic that is reused throughout your application. Subscribe to premium projects and start being productive today.

Sunday, April 5, 2009PrintSubscribe
Present What You Want

Data Aquarium Framework offers users of your applications impressive data filtering and reporting capabilities. Nevertheless there will always be a situation when you need to present a specific database record or a group of records on demand.

Filtering Via URL Parameter

The simplest method is to redirect your user to a specific page while supplying a record ID in the URL. For example, navigate to http://dev.codeontime.com/demo/nwblob/?EmployeeID=5 and you will see an employee with EmployeeID equal to 5 presented in the list.

image

Remove EmployeeID from the URL and all employees are displayed.

image

You are not limited to the record IDs only. For example, the following URL will select all employees with job title “Sales Representative” working in London office:

http://dev.codeontime.com/demo/nwblob?Title=Sales%20Representative&City=London

image

If the filtered field is visible by default then Data Aquarium Framework will automatically hide the corresponding field column in the grid view since the field value is presumed to be known to the user. There is little value repeating “Sales Representative” and “London” in each row in the picture above. You may want to verify that each employee is indeed working in London and has the title that we have specified.

Filtering Via an Element on The Page

You can also point your DataViewExtender components to read the filter value form any element on the page.

Add ~/Products.aspx page to the Data Aquarium project generated from Northwind database. Modify this page as shown below.

<%@ Page Title="" Language="C#" MasterPageFile="~/MasterPage.master" 
    AutoEventWireup="true" CodeFile="Products.aspx.cs" 
    Inherits="Products" %>

<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="Server">
    <style type="text/css">
        div.Caption
        {
            font-weight: bold;
            padding: 4px 4px 4px 4px;
            background-color: #FDEAB1;
            color: #60302A;
        }
    </style>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="Header1Placeholder" 
        runat="Server">
    Products
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="Header2Placeholder" 
        runat="Server">
    Northwind
</asp:Content>
<asp:Content ID="Content4" ContentPlaceHolderID="BodyPlaceholder" 
        runat="Server">
    <asp:HiddenField ID="ProductID" runat="server" Value="5" />
    <!-- "edit" mode -->
    <div class="Caption">
        "Edit" Mode</div>
    <div id="EditProduct" runat="server">
    </div>
    <aquarium:DataViewExtender ID="DataViewExtender1" runat="server" 
        TargetControlID="EditProduct"
        Controller="Products" 
        FilterSource="ProductID" FilterFields="ProductID" 
        ShowActionBar="false"
        StartCommandName="Edit" StartCommandArgument="editForm1" />
    <!-- "new" mode -->
    <div class="Caption">
        "New" Mode</div>
    <div id="NewProduct" runat="server">
    </div>
    <aquarium:DataViewExtender ID="DataViewExtender2" runat="server" 
    TargetControlID="NewProduct"
        Controller="Products" ShowActionBar="false" 
        StartCommandName="New" StartCommandArgument="createForm1"
        PageSize="1" />
    <!-- "read" mode -->
    <div class="Caption">
        "Read" Mode</div>
    <div id="ViewProduct" runat="server">
    </div>
    <aquarium:DataViewExtender ID="ProductListExtender" runat="server" 
        TargetControlID="ViewProduct"
        Controller="Products" 
        FilterSource="ProductID" FilterFields="ProductID" 
        ShowActionBar="false"
        StartCommandName="Select" StartCommandArgument="editForm1" />
</asp:Content>

You can see this page live at http://dev.codeontime.com/demo/filtering

At the top of the page there is HiddenField server control ProductID with its value set to 5.

    <asp:HiddenField ID="ProductID" runat="server" Value="5" />

Three different views are presented on the page. Let’s take a look at each of them.

The first view presents data in edit mode.

    <!-- "edit" mode -->
    <div class="Caption">
        "Edit" Mode</div>
    <div id="EditProduct" runat="server">
    </div>
    <aquarium:DataViewExtender ID="DataViewExtender1" runat="server" 
        TargetControlID="EditProduct"
        Controller="Products" 
        FilterSource="ProductID" FilterFields="ProductID" 
        ShowActionBar="false"
        StartCommandName="Edit" StartCommandArgument="editForm1" />

It uses hidden field as a filter source and filters by the field ProductID.  The startup command displays view editForm1 in edit mode.

image

The second view displays an empty record and does not specify any filter.

    <!-- "new" mode -->
    <div class="Caption">
        "New" Mode</div>
    <div id="NewProduct" runat="server">
    </div>
    <aquarium:DataViewExtender ID="DataViewExtender2" runat="server" 
        TargetControlID="NewProduct"
        Controller="Products" ShowActionBar="false" 
        StartCommandName="New" StartCommandArgument="createForm1"
        PageSize="1" />

The startup command is executed only after the data controller data is transferred to the client browser. This will cause the controller to read the first page of records from the database. We are reducing the number of returned records to one by specifying the corresponding page size. You can eliminate retrieval of any records if you link a business rules filter to the Products data controller.

Here is the screen shot of the view.

image

The third view uses the hidden field as a filter source to display a view of a single record in “read” mode in editForm1.

    <!-- "read" mode -->
    <div class="Caption">
        "Read" Mode</div>
    <div id="ViewProduct" runat="server">
    </div>
    <aquarium:DataViewExtender ID="ProductListExtender" runat="server" 
        TargetControlID="ViewProduct"
        Controller="Products" 
        FilterSource="ProductID" FilterFields="ProductID" 
        ShowActionBar="false"
        StartCommandName="Select" StartCommandArgument="editForm1" />

Here is how the view looks when rendered in a web browser.

image

Generated data controllers are configured by default to switch to grid1 view when user successfully executes Insert, Update, Delete, or Cancel command. You may want to play with configuration of actions in ~/Controls/Products.xml to make do what you see fit for your purposes. Read about it here.

Preventing Filtering

You may also want to prohibit any filtering at all. This is easy to accomplish if you assign None to the FilterSource property of the DataViewExtender component.

<aquarium:DataViewExtender ID="ProductExtender" runat="server" 
    TargetControlID="ProductList" Controller="Products" 
    FilterSource="None" />

Conclusion

It is very easy to filter and display records that you want to be presented. URL parameters and elements on the page can be automatically consumed as sources of filter values.

Next we will take a look at server-side filtering via code in business rules.

Saturday, April 4, 2009PrintSubscribe
ExternalFilter And Modal Views

New ExternalFilter property is available to business rules developers and allows implementing code that is aware of the external master-detail relationships without mixing business logic and user interface code and markup.

image

Sample Project

You can see this sample live at http://dev.codeontime.com/demo/externalfilter. The source code is available at http://dev.codeontime.com/demo/externalfilter/Source.zip.

Generate a Data Aquarium application from Northwind database with business objects enabled and add ~/EmployeeTerritories.aspx page to the root of the web site created by Code OnTime Generator.

Open ~/Controllers/EmployeeTerritories.xml and create its copy named ~/Controllers/MyEmployeeTerritories.xml. Change view grid1 to reveal the territory code and add territory description as a separate field.

<view id="grid1" type="Grid" commandId="command1" label="Employee Territories">
    <headerText>This is a list of employee territories. </headerText>
    <dataFields>
        <dataField fieldName="EmployeeID"/>
        <dataField fieldName="TerritoryID" />
        <dataField fieldName="TerritoryTerritoryDescription"/>
        <dataField fieldName="TerritoryRegionRegionDescription"/>
    </dataFields>
</view>

Modify EmployeeTerritories.aspx as shown in this snippet.

<%@ Page Title="" Language="C#" MasterPageFile="~/MasterPage.master" 
    AutoEventWireup="true" CodeFile="EmployeeTerritories.aspx.cs" 
    Inherits="EmployeeTerritories" %>

<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="Header1Placeholder" runat="Server">
    Employee Territories
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="Header2Placeholder" runat="Server">
    Northwind
</asp:Content>
<asp:Content ID="Content4" ContentPlaceHolderID="BodyPlaceholder" runat="Server">
    <div id="EmployeesDiv" runat="server">
    </div>
    <aquarium:DataViewExtender ID="EmployeesExtender" runat="server" 
        Controller="Employees"
        PageSize="5" TargetControlID="EmployeesDiv" />
    <div id="EmployeeTerritoriesDiv" runat="server" />
    <aquarium:DataViewExtender ID="EmployeeTerritoriesExtender" runat="server" 
        Controller="MyEmployeeTerritories" 
        TargetControlID="EmployeeTerritoriesDiv" FilterFields="EmployeeID" 
        FilterSource="EmployeesExtender"
        PageSize="20" />
</asp:Content>

Open the page in the browser. The following user interface will be presented.

image

Task

Users can quickly associate selected employee and territories by clicking New | New Employee Territories option on the action bar of Employee Territories view.

We will add a new option to New menu to allow simultaneous creation of a new territory and association of this territory with the selected employee. We will be using modal dialog and ExternalFilter property for this task.

Implementation

Add the new action to MyEmployeeTerritories.xml.

<actionGroup scope="ActionBar" headerText="New">
    <action commandName="New" commandArgument="createForm1" 
        headerText="New Employee Territories" 
        description="Create a new Employee Territories record." />
    <action commandName="Custom" commandArgument="CreateAndLinkTerritory" 
        headerText="Create and Link Territory" 
        description="Create a new Territory and link it to employee." 
        cssClass="NewLargeIcon"/>
</actionGroup>

image 

Modify command1 and add new command2 as follows.

        <command id="command1" type="Text">
            <text>
                <![CDATA[
select
    "EmployeeTerritories"."EmployeeID" "EmployeeID"
    ,"Employee"."LastName" "EmployeeLastName"
    ,"EmployeeTerritories"."TerritoryID" "TerritoryID"
    ,"Territory"."TerritoryDescription" "TerritoryTerritoryDescription"
    ,"TerritoryRegion"."RegionDescription" "TerritoryRegionRegionDescription"
    ,null "TerritoryCode"
    ,null "TerritoryDescription"
    ,null "RegionID"
from "dbo"."EmployeeTerritories" "EmployeeTerritories"
    left join "dbo"."Employees" "Employee" on "EmployeeTerritories"."EmployeeID" = "Employee"."EmployeeID"
    left join "dbo"."Territories" "Territory" on "EmployeeTerritories"."TerritoryID" = "Territory"."TerritoryID"
    left join "dbo"."Region" "TerritoryRegion" on "Territory"."RegionID" = "TerritoryRegion"."RegionID"
]]>
            </text>
        </command>
        <command id="command2" type="Text">
            <text>
                <![CDATA[
select
    null "EmployeeID"
    ,null "EmployeeLastName"
    ,null "TerritoryID"
    ,null "TerritoryTerritoryDescription"
    ,null "TerritoryRegionRegionDescription"
    ,null "TerritoryCode"
    ,null "TerritoryDescription"
    ,null "RegionID"
    
]]>
            </text>
        </command>
    </commands>
    <fields>

Notice that command1 was enhanced with three additional fields TerritoryCode, TerritoryDescription, and RegionID that are being selected as empty values. Command command2 mirrors all fields of command1 with one exception - all fields are returned as NULL values. The second command returns a single row of empty values.

Let's add definitions of the new fields to the fields element of the data controller.

<!-- new fields to support "createTerritory" view -->
<field name="TerritoryCode" type="String" allowNulls="false" label="Code"/>
<field name="TerritoryDescription" type="String" allowNulls="false" label="Description"/>
<field name="RegionID" type="Int32" allowNulls="false" label="Region">
    <items style="ListBox" dataController="Region" />
</field>

Finally, we will add createTerritory view. This view will be displayed in response to a selection of Create and Link Territory action bar menu option and is relying on command2 for its data.

<view id="createTerritory" type="Form" commandId="command2" 
    label="Create New Territory">
    <headerText>Please fill this form and click OK button to create 
        a new territory and link it to the employee. Click Cancel 
        to return to the previous screen.</headerText>
    <categories>
        <category headerText="Employee Information">
            <description>New territory will be linked to this employee.</description>
            <dataFields>
                <dataField fieldName="EmployeeLastName"/>
            </dataFields>
        </category>
        <category headerText="Territory">
            <description><![CDATA[
                Please enter the territory code, territory description, and 
                select a territory region. <br/><br/>You can use zip code 
                of the territory as code and city or county name as 
                territory description.]]></description>
            <dataFields>
                <dataField fieldName="TerritoryCode" columns="5"/>
                <dataField fieldName="TerritoryDescription" />
                <dataField fieldName="RegionID" />
            </dataFields>
        </category>
    </categories>
</view>

Now we are ready to write some code. Data Aquarium Framework promotes business logic reusability. Custom code is implemented in independent classes that are hooked to data controllers via @handler attribute.

Create a new class Class1 and link the class to data controller.

<dataController name="EmployeeTerritories" 
    conflictDetection="overwriteChanges" 
    label="Employee Territories" 
    xmlns="urn:schemas-codeontime-com:data-aquarium" 
    handler="Class1">
    ......

Enter the following code in the class definition.

C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using MyCompany.Data;
using MyCompany.Data.Objects;

public class Class1 : BusinessRules
{
    public Class1()
    {
    }

    [ControllerAction("MyEmployeeTerritories", 
        "Custom", "CreateAndLinkTerritory")]
    protected void NewTerritory()
    {
        if (Arguments.ExternalFilter.Length > 0 
            && Arguments.ExternalFilter[0].Value != null)
        {
            Employees emp = Employees.SelectSingle(
                Convert.ToInt32(Arguments.ExternalFilter[0].Value));
            Context.Session["Employee"] = emp;
            Context.Session["ControllerID"] = Arguments.ContextKey;
            Result.ShowModal("MyEmployeeTerritories", "createTerritory", 
                "New", "createTerritory");
        }

        else
            Result.ShowAlert("Please select an employee.");
    }

    [RowBuilder("MyEmployeeTerritories", 
        "createTerritory", RowKind.New)]
    protected void CreateTerritoryNewRow()
    {
        Employees emp = (Employees)Context.Session["Employee"];
        UpdateFieldValue("EmployeeLastName", emp.LastName);
    }

}

VB

Imports Microsoft.VisualBasic
Imports MyCompany.Data
Imports MyCompany.Data.Objects

Public Class Class1
    Inherits BusinessRules

    <ControllerAction("MyEmployeeTerritories", _
        "Custom", "CreateAndLinkTerritory")> _
    Protected Sub NewTerritory()
        If (Arguments.ExternalFilter.Length > 0 _
                AndAlso Not Arguments.ExternalFilter(0).Value Is Nothing) Then
            Dim emp As Employees = Employees.SelectSingle( _
                Convert.ToInt32(Arguments.ExternalFilter(0).Value))
            Context.Session("Employee") = emp
            Context.Session("ControllerID") = Arguments.ContextKey
            Result.ShowModal("MyEmployeeTerritories", "createTerritory", _
                             "New", "createTerritory")
        Else
            Result.ShowAlert("Please select an employee.")
        End If
    End Sub

    <RowBuilder("MyEmployeeTerritories", _
                "createTerritory", RowKind.New)> _
    Protected Sub CreateTerritoryNewRow()
        Dim emp As Employees = CType(Context.Session("Employee"), Employees)
        UpdateFieldValue("EmployeeLastName", emp.LastName)
    End Sub

End Class

Class Class1 is inherited from BusinessRules base. Business rules are recognized by the framework. Business rules class members are treated as serving a specific purpose when adorned with certain attributes.

Attribute ControllerAction on method NewTerritory will instruct the framework to invoke this method whenever a custom command with argument CreateAndLinkTerritory is invoked in a client-side JavaScript component Web.DataView.

Business rules property Arguments gives access to all information about the incoming command request. Its own new property ExternalFilter allows inspecting values of a master-detail link when a Web.DataView component is linked as a child in such a relationship. At the top of the article we have configured EmloyeeTerritoriesExtender component to be filtered by EmployeeID field. The extender injects a JavaScript snippet into the page to create an instance of Web.DataView with the appropriate filter.

Method NewTerritory verifies if an employee is selected and then stores the selected employee information in the web request session and displays a view createTerritory in a modal mode. The startup command for the view is New with an argument that points to the view itself. This will cause the view to be displayed in the "new record" mode.

image

In the screen shot you can see this in action.

Note that employee name corresponds to the name of the employee selected in the list of employees. The name is provided by method CreateTerritoryNewRow adorned with an attribute RowBuilder. This method retrieves selected employee from the session and updates the row returned with employee's last name just before the row is returned to the client.

If you set a break point in method CreateTerritoryNewRow then the debugger will stop there twice. It happens for the first time when view is initialized for modal presentation. Then the startup command is executed to switch the view in the "new record" mode, which causes the second invocation. The framework does not distinguish views to be serving any specific purpose and assumes the "new record" mode only when the New command has been executed.

The following code will create a new territory and link it to the selected employee by create a new record in EmployeeTerritories table. This code will execute when user clicks the OK button.

C#

[ControllerAction("MyEmployeeTerritories", "createTerritory", 
    "Insert", ActionPhase.Before)]
protected void NewTerritorySave(string territoryCode, 
    string territoryDescription, int regionId)
{
    PreventDefault();
    Employees emp = (Employees)Context.Session["Employee"];
    Territories t = new Territories();
    t.TerritoryID = territoryCode;
    t.TerritoryDescription = territoryDescription;
    t.RegionID = regionId;
    if (t.Insert() == 1)
    {
        EmployeeTerritories et = new EmployeeTerritories();
        et.TerritoryID = t.TerritoryID;
        et.EmployeeID = emp.EmployeeID;
        et.Insert();
    }
    Result.HideModal();
    Result.ExecuteOnClient(
        String.Format("$find('{0}').goToPage(-1)", 
        Context.Session["ControllerID"]));
}

VB

<ControllerAction("MyEmployeeTerritories", "createTerritory", _
                      "Insert", ActionPhase.Before)> _
    Protected Sub NewTerritorySave(ByVal territoryCode As String, _
        ByVal territoryDescription As String, ByVal regionId As Integer)
        PreventDefault()
        Dim emp As Employees = CType(Context.Session("Employee"), Employees)
        Dim t As Territories = New Territories()
        t.TerritoryID = territoryCode
        t.TerritoryDescription = territoryDescription
        t.RegionID = regionId
        If t.Insert() = 1 Then
            Dim et As EmployeeTerritories = New EmployeeTerritories()
            et.TerritoryID = t.TerritoryID
            et.EmployeeID = emp.EmployeeID
            et.Insert()
        End If
        Result.HideModal()
        Result.ExecuteOnClient( _
            String.Format("$find('{0}').goToPage(-1)", _
            Context.Session("ControllerID")))

    End Sub

Command command2 is not based on any real database table. We are intercepting a request from createTerritory view to insert a new record via NewTerritorySave method. Any data fields available in the view can be listed as parameters of the method.

First, we prevent any default logic from executing when our method exits by calling PreventDefault.

Then we use the automatically generated business objects Employees, Territories, and EmployeeTerritories to update the database. Business objects are not equipped with database connections or commands, which allows storing them safely in ASP.NET session. Data manipulation commands are executed by business objects via Data Aquarium Framework. Business objects rely on the same data controller architecture to promote business logic reuse.

Last, we have to hide the modal view displayed at the moment in the user's browser. The request is executed in the context of the client side view createTerritory. Many methods available via business rules Result property are producing small snippets of JavaScript that are being accumulated while the request is processed on the server. Nothing happens until the method exists and the batch is returned to the browser.

Most likely you would want the employee territories refreshed and display a new territory that employee is responsible for. The last line of the method sends a JavaScript command to the browser to refresh the view that has requested displayed of createTerritory view in the first place. Client ID of the view was available in NewTerritory method via Arguments.ContextKey property.

Conclusion

Simple and power business rules model of Data Aquarium Framework allows archiving functionality of a significant complexity with a very modest amount of code. Database interactions are greatly simplified by business objects automatically generated by Code OnTime Generator.

Business rules and objects are available to subscribers to premium projects only.

Continue to Hiding View Selector