FREE hit counter and Internet traffic statistics from

Tuesday, November 16, 2004

Organizing Domain Logic: Table Module

The second pattern for representing domain logic is the Table Module. As the name implies this pattern calls for a Business Component to map to a table in the database. The component then contains all the domain logic methods required to manipulate the data. There are two key considerations here.

First, although the name refers to a table, Table Module can also be used to abstract frequently used sets of data created by joining multiple tables together in a view or query. This makes dealing with more complicated data much easier for the caller to the Business Components.

Second, the core characteristic of each component built as a Table Module is that, unlike Domain Model, it has no notion of identity. In other words, each Table Module object represents a set of rows rather than a single row and therefore in order to operate on a single row, the methods of the table module must be passed in identifiers.

When a method of a Table Module is called, it performs its logic against a set of rows passed into it. In Framework applications this maps to a DataSet and is therefore a natural way to represent domain logic. In fact, using Typed DataSets with Table Module is particularly effective since it promotes strong typing at design time leading to fewer runtime errors and better control over the data flowing through the application.

A common approach to handling this is to create a Layer Supertype (a pattern also discussed by Fowler) or base class for all of the Table Modules that accepts a DataSet in its constructor. This also allows the Business Components to be tested without a live connection to a database.

To implement a Table Module approach in the retail application example you could create an abstract BusinessComponentBase class like that shown here. This class is responsible for accepting the DataSet that the class will work on, exposing individual rows in the DataSet using the default (VB) or indexer (C#) property, and exposing the entire set of rows in a readonly property.

As you can see one of the advantages to using Table Module over Transaction Script is that it is easier to encapsulate responsibilities with the appropriate objects. Here the Customers class contains the SendEmail and CheckCredit methods that can be called independently whereas the Transaction Script shown previously would have included inline code to handle this.
The code to implement the BusinessComponentBase class can be seen below.

Public MustInherit Class BusinessComponentBase
Private _ds As DataSet
Private _pk As String
Protected Sub New(ByVal data As DataSet)
_ds = data
_pk = _ds.Tables(0).PrimaryKey(0).ColumnName
End Sub
Default Protected ReadOnly Property Item(ByVal id As Integer) As DataRow
Dim f As String = _pk & " = " & id
Return _ds.Tables(0).Select(f)(0)
End Get
End Property
Protected ReadOnly Property Items() As DataSet
Return _ds
End Get
End Property
End Class

Note that the protected constructor finds the primary key column and stores its value in a private variable used by the Item property to select and return a particular DataRow.

This class can then be inherited by Orders and Customers. The Orders class in C# is shown here.

public class Orders : BusinessComponentBase
public new OrdersDs Items
{ get { return (OrdersDs)base.Items; }
public Orders(OrdersDs orders):base(orders)
{ }
public ShipType GetShipType(long orderId)
// Return the shipping type for the order
public double GetShippingCost(long orderId)
// Calculate the shipping costs for the order
public void SaveOrder(long orderId)
// Save the specific order to the database
public void SaveOrder()
// Save all the orders to the database
public long Insert(long productId, int customerId,
long quantity, ShipType ship)
// Insert a new row in the DataSet

The main point to notice here is that the constructor accepts a DataSet of type OrdersDs which is a Typed DataSet. The class then shadows the Items method in order to return a strongly typed DataSet. Also, this is a good place to take advantage of overloading as in the SaveOrder method which can be used to save either one order or all of the orders in the DataSet.

A client can then instantiate the Orders class passing into it the OrdersDs DataSet.
Orders o = new Orders(dsOrders);o.Save(123324);


Anonymous said...

Do want to know the magic of online games, and here you can get more ro zeny. Do you want to have a try? Come on and ragnarok zeny can make you happy.You can change a lot iro zeny for play games. And you will enjoy yourself at the same time. Playing online games can make much cheap zeny. And you can use the ragnarok online zeny do what you want to do in the online game. Come and join with us. We are waiting for your coming.

Anonymous said...

Microsoft Office
Office 2010
Microsoft Office 2010
Office 2010 key
Office 2010 download
Office 2010 Professional
Microsoft outlook
Outlook 2010
Windows 7
Microsoft outlook 2010

Love Kpop said...

Not all are true. Everyone has their own way of thinking but I think they have to reconsider. I like to argue for the most accurate results.