Business Rules/Logic

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
Business Rules/Logic
Sunday, January 13, 2013PrintSubscribe
Validation with SQL Business Rules

It is a requirement for every database web application to perform data validation. SQL business rules can be used to extend the functionality of basic database validation to ensure that the user enters values that conform to business requirements.

Server-side validation has the benefit of direct access to database and sophisticated APIs of the server-side operating system and database engine. One major limitation is the inability to have a conversation with the user – the server-side code cannot ask questions of the user without complex chained internet callbacks. If the business rule implementation requires confirming certain aspects of validation by directly requesting information from the application user, then a validating JavaScript business rule must be implemented. If a “conversational” validation business logic requires access to the database, then consider utilizing the RESTful application server of your web app.

Consider the following example below. The default Northwind web application allows users to select a product and enter any unit price, quantity, and discount. The database engine will validate the constraints and raise an exception if an error occurs.

Basic database engine validation in action.

However, the database server will not test for logical violations, such as absurd unit price or quantity.

Let’s implement an SQL business rule that will perform multi-step validation.

Configuring Fields

Start the Project Designer. Switch to the Controllers tab in the Project Explorer. Double-click on OrderDetails / Fields / ProductID* (Int32) –> Products node.

Field 'ProductID' of Order Details controller.

Change the following:

Property Value
Copy UnitPrice=UnitPrice

Press OK to save. Next, double-click on UnitPrice* (Decimal) field node.

'UnitPrice' field of Order Details controller.

Make the following changes:

Property Value
The value of this field is calculated by a business rule expression. true
Context Fields ProductID, UnitPrice, Quantity, Discount

Press OK to save.

Configuring Business Rule

Right-click on OrderDetails / Business Rules node, and press New Business Rule.

Creating a new business rule for OrderDetails controller.

Assign the following values:

Property Value
Type SQL
Command Name Calculate|Insert|Update
Phase Execute

Paste in the following script:

-- 1. If the collected values are not valid then do not enforce the rule.
--    The client library will instruct the user to correct the input.
declare @Success nvarchar (5) = 'true'

-- 2. Reset the base price for calculation of price limits
--    if the product selection has changed or if an existing
--    data row has been selected for editing
if (@ProductID != @Session_ProductID or @Session_ProductID is null)
begin
    declare @BasePrice decimal = @UnitPrice
    if (@Arguments_Trigger != 'ProductID')
    begin
        set @BasePrice = @UnitPrice_OldValue
    end
    set @Session_UnitPrice = @BasePrice
    set @Session_ProductID = @ProductID
    if (@Arguments_Trigger = 'ProductID')
    begin
        set @Quantity = 1
        set @Discount = 0
        set @Result_Focus = 'Quantity'
    end
end

-- 3. Adjusting base price for an existing record
declare @OriginalUnitPrice float = @Session_UnitPrice
if (@Session_UnitPrice is null)
begin
    set @OriginalUnitPrice = @UnitPrice_OldValue
    set @Session_UnitPrice = @OriginalUnitPrice
end

-- 4. Validate Unit Price Field
declare @MinPrice float = @OriginalUnitPrice
declare @MaxPrice float = (@OriginalUnitPrice * 1.05)
if (@UnitPrice is null)
    set @Result_Focus = 'UnitPrice, Please enter the price.'
else
    if (@UnitPrice < @MinPrice or @UnitPrice >= @MaxPrice)
        set @Result_Focus = 'UnitPrice, The price must be between $' 
                        + cast(convert(money, @MinPrice) as nvarchar(50)) + ' and $' 
                        + cast(convert(money, @MaxPrice) as nvarchar(50)) + '.'
        set @Success = 'false'

-- 5. Validate Quantity Field
if (@Quantity is not null and @Quantity <= 0)
begin
    set @Result_Focus = 'Quantity, The quantity must be greater than zero.'
    set @Success = 'false'
end

-- 6. Validate Discount Field
if (@Discount > 1)
    set @Discount = (@Discount / 100)

-- 7. Confirm Discount is between 0.00 and 0.99
if (@Discount is not null and (@Discount < 0.00 or @Discount > 0.99))
begin
    set @Result_Focus = 'Discount, The discount must be between 0.00 and 0.99 (0% - 99%).'
    set @Success = 'false'
end

-- 8. Wrapping up
if (@Arguments_CommandName = 'Calculate' or @Success = 'false')
    set @BusinessRules_PreventDefault = 1

The business rule will be fired when a user inserts a new record, updates an existing record, and every time a field value is changed. The client library will first ensure that the values are valid. Then the script will be sent to the database server. The field values are bound by the application framework as @FieldName. Session variables are introduced to the web application by using @Session_FieldName. The name of the field that triggered the command is recorded in @Arguments_Trigger, and the command is saved in @Arguments_Command. The client library is instructed to display messages next to fields using @Result_Focus. The parameter @BusinessRules_PreventDefault will prevent the default behavior of the web application from continuing.

There are eight distinct steps to this business rule:

1. Initial Input Validation

When a user enters an invalid value in the Order Details form, the client library will display an error and prevent execution of the business rule – no code needs to be written for this to occur.

The variable @Success is declared in order to remember the status of validation. By default, it is set to “true”. If any of the later steps fail to validate, this variable will be changed to “false” and the last step will ensure that the user cannot apply changes.

declare @Success nvarchar (5) = 'true'

The picture below shows an example of automatic client-side validation.

Example of automatic client-side validation.

2. Determination of the “Base” Price

This query will memorize the last ProductID and UnitPrice values in session variables, as well as the UnitPrice of the selected product when it is copied over. This UnitPrice will be saved as @BasePrice, and will be used to prevent price inflation by more than 5%. When the ProductID is changed, the Quantity and Discount fields will be reset to default values of 1 and 0.

if (@ProductID != @Session_ProductID or @Session_ProductID is null)
begin
    declare @BasePrice decimal = @UnitPrice
    if (@Arguments_Trigger != 'ProductID')
    begin
        set @BasePrice = @UnitPrice_OldValue
    end
    set @Session_UnitPrice = @BasePrice
    set @Session_ProductID = @ProductID
    if (@Arguments_Trigger = 'ProductID')
    begin
        set @Quantity = 1
        set @Discount = 0
        set @Result_Focus = 'Quantity'
    end
end

The screenshot below shows the form after the product has been changed.

Selecting a new product will reset Unit Price, Quantity, and Discount.

3. Adjusting Base Price for Existing Records

If the user is editing an existing record, then the original UnitPrice value is memorized using a session variable.

declare @OriginalUnitPrice float = @Session_UnitPrice
if (@Session_UnitPrice is null)
begin
    set @OriginalUnitPrice = @UnitPrice_OldValue
    set @Session_UnitPrice = @OriginalUnitPrice
end

4. Price Validation

The minimum and maximum price is calculated. If the price is blank, the user is directed to enter a value. If the price is out of range, the user is forced to correct the problem.

declare @MinPrice float = @OriginalUnitPrice
declare @MaxPrice float = (@OriginalUnitPrice * 1.05)
if (@UnitPrice is null)
    set @Result_Focus = 'UnitPrice, Please enter the price.'
else
    if (@UnitPrice < @MinPrice or @UnitPrice >= @MaxPrice)
        set @Result_Focus = 'UnitPrice, The price must be between ' 
                        + cast(@MinPrice as nvarchar(50)) + ' and ' 
                        + cast(@MaxPrice as nvarchar(50)) + '.'
        set @Success = 'false'

The form below shows price validation in action.

Price validation in form view on Unit Price field.

Here is validation in data sheet view.

Price validation in Order Details data sheet view.

5. Quantity Validation

Validation will ensure that a positive value is entered into Quantity field.

if (@Quantity is not null and @Quantity <= 0)
begin
    set @Result_Focus = 'Quantity, The quantity must be greater than zero.'
    set @Success = 'false'
end
Validation of a positive integer in Quantity field.

6. Automatic Conversion of Discount

When the user enters a value greater than 1, the business rule will automatically convert the value to a fraction of 100.

if (@Discount > 1)
    set @Discount = (@Discount / 100)

For example, a value of “25” has been entered in the New Order Details screen shown below.

Discount field value of '25' is entered.

When focus is shifted from the field, the value is converted to a percentage.

The value of Discount is converted into a percentage.

7. Discount Range Validation

A validation error will be displayed if the Discount value is not within range after automatic conversion.

if (@Discount is not null and (@Discount < 0.00 or @Discount > 0.99))
begin
    set @Result_Focus = 'Discount, The discount must be between 0.00 and 0.99 (0% - 99%).'
    set @Success = 'false'
end
Percentage validation of 'Discount' field.

8. Wrapping Up

The default behavior of the application server will be to continue processing the Insert or Update action triggered by the user. If any of the validations have failed or the command was Calculate, the default behavior will be halted.

-- 8. Wrapping up
if (@Arguments_CommandName = 'Calculate' or @Success = 'false')
    set @BusinessRules_PreventDefault = 1
Saturday, January 5, 2013PrintSubscribe
Interacting with the Client Library

Server-side code can take advantage of the application client library by registering snippets of JavaScript rendered on the server.

Let’s set up a user control with a button. When the button is pressed, an alert will be shown and a message displayed in the message bar at the top of the page.

Creating User Control

Start the Project Designer. On the Project Explorer toolbar, click on the New Page icon.

Creating a new page using the icon on the Project Explorer toolbar.

Assign a name:

Property Value
Name Test

Press OK to save. Drop Test page node on the right side of Home page node to place it second in the hierarchy.

Dropping 'Test' page node on the right side of 'Home' page node.     Page 'Test' has been placed second in the hierarchy.

Right-click on the page, and press New Container.

Creating a new container for page 'Test'.

Preserve the default values and press OK to save.

Right-click on the new container, and press New Control.

Creating a new control.

Next to the User Control lookup in the Project Browser, click on the New User Control icon.

Creating a new user control using the 'New User Control' icon.

Assign the user control a name:

Property Value
Name DisplayAlert

Press OK to save the user control and insert it. Press OK again to save the control.

Modifying the User Control

On the toolbar, press Browse to generate the user control file. When complete, right-click on Test / c101 / control1 – DisplayAlert node, and press Edit in Visual Studio.

Editing the user control in Visual Studio.

The user control will open in Visual Studio. Press Ctrl+K, Ctrl+D keyboard shortcut to format. Replace the code after the <%@ Control %> element with the following:

<asp:UpdatePanel ID="UpdatePanel1" runat="server">
    <ContentTemplate>
        <div style="margin: 2px; border: solid 1px silver; padding: 8px;">
            <asp:Button ID="Button1" runat="server" 
                OnClick="Button1_Click" Text="Button" />
        </div>
    </ContentTemplate>
</asp:UpdatePanel>

The user control will display a button that will perform the “Button1_Click” method handler when pressed. In the Solution Explorer, double-click on ~\Controls\DisplayAlert.ascx\DisplayAlert.ascx.cs file. Add the following method to the file:

C#:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class Controls_DisplayAlert : System.Web.UI.UserControl
{
    
    protected void Page_Load(object sender, EventArgs e)
    {
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        ScriptManager.RegisterStartupScript(this.Page,
            this.Page.GetType(), "test1",
            "alert('hello')", true);
        ScriptManager.RegisterStartupScript(this.Page,
            this.Page.GetType(), "test2",
            "Web.DataView.showMessage('hello')", true);
    }
}

Visual Basic:

Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text.RegularExpressions
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls


Partial Public Class Controls_DisplayAlert
    Inherits Global.System.Web.UI.UserControl
    
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
    End Sub
    Protected Sub Button1_Click(ByVal sender As Object,
                                ByVal e As EventArgs)
        ScriptManager.RegisterStartupScript(Me.Page, Me.Page.GetType(),
                                            "test1", "alert('hello')", True)
        ScriptManager.RegisterStartupScript(Me.Page, Me.Page.GetType(),
                                            "test2", "Web.DataView.showMessage('hello')", True)
    End Sub
End Class

The method will show an alert using the standard alert method. A message is shown at the top of the page with the help of the client library method Web.DataView.showMessage. Save the file, and switch to the web application.

Viewing the Results

Navigate to the Test page. Click on the button in the center of the page. An alert will open with the text “hello”.

image

Press OK to dismiss the alert. A message will be displayed at the top of the page with the text “hello”.

image

Wednesday, January 2, 2013PrintSubscribe
Custom Business Rule for Duplicate Action

The default behavior of Duplicate action is to execute the New action and automatically copy values from the current row into the fields of the record. If it is necessary to change the default behavior, a custom business rule must be used.

A user can duplicate a customer using the Duplicate context menu option in Customers grid.

Duplicate context menu action for a row in Customers grid.

The create form will be opened. Fields will be populated using the values of the original record.

Duplicate causes the New Customers form to open with the same values as the original record.

Let’s add a business rule that will add an asterisk (*) to the Customer# field.

Start the Project Designer. In the Project Explorer, switch to the Controllers tab. Right-click on Customers / Business Rules node, and press New Business Rule.

Creating a new business rule for Customers controller.

Assign these values:

Property Value
Type JavaScript
Command Name New
Phase After
Script
[CustomerID] = [CustomerID] + '*';

Press OK to save. On the toolbar, press Browse.

Navigate to the Customers page. Activate the context menu for a row and press Duplicate.

Activating 'Duplicate' context menu option for a Customers record.

The Customer# value will be appended with an asterisk.

The 'CustomerID' field is appended with an asterisk.

This Duplicate action is only client-side. The data is only saved to the server when the user presses OK.

More complex duplication calculations that require database interaction can be implemented with the use of REST (Representational State Transfer) or with the use of SQL Business Rules.