wwBusiness<T>: Entity based Business Objects

Entity based business objects provide a strongly typed Entity member that maps the fields of the mapped database table. wwBusiness<T> uses generics to assign the entity type and so provide a simple way to expose the Entity property. The overall behavior of the business object is identical to the base wwBusiness type from which it inherits with the additional Entity behavior added.

The process to configure an Entity based business object requires that an Entity object actually exists. Entity objects are classes that inherit from Westwind.BusinessObjects.wwDataRowContainer and they are generally generated automatically from database tables. The EntityGenerator.exe tool provides this functionality.

The steps to create an Entity based business object are:

Typed Entities

wwBusiness<T> uses Entity classes that attach to the business objects. The framework ships with a utility that can create Entity classes from your Database tables. The generator basically creates one class per table that you specify (or all of them) and creates a strongly typed class for each with properties for each of the fields. This is similar to a typed DataRow in a typed DataSet, but it's much more light weight in that it doesn't load up the whole DataSet scheme to use a single item. Instead the Entity mechanism simply reads DataRow values.

The entities are attached on demand only and are bound to the business objects as a simple property. For example, to load an invoice, update the invoice date and save:

Invoice.Load(10221); DateTime dt = Invoice.Entity.InvDate; Invoice.Entity.InvDate = DateTime.Now.Date; Invoice.Save();

The entity objects are automatically initialized by the business framework through the Generic type definition of the wwBusiness class:

public class busInvoice : wwBusiness<wws_invoiceRow>

where wws_Invoice is the Entity object that becomes the Entity member that is exposed.

The entities are bound to an underlying DataRow member, but they are not dependent on it if no DataRow is loaded. This is important so objects can properly serialize and deserialize - the Entity acts like a normal .NET object with its own data storage fields that can serialize and deserialize without taking the DataRow with it.

Creating the Entities with the EntityGenerator Tool

The easiest way to generate Entity classes is to run the EntityGenerator tool which can be found in the Start Group or in the \TOOLS directory of your Web Store installation. When run it looks like this:

The basic concept of the generator is to point at a database with a connection string. You then specify a number of properties on how you want to create the classes, select tables to import, select an output file and then click generate to create the file. Generate the file into your business object project directory and add it to the project.

Once you've generated the entity source file, the file contains the configuration settings that were used to generated. You can reload the file into the generator to retrieve these settings so re-generating is a lot easier.

Create the Class

Once the entities have been created you can then start creating business objects that are based on it. To do this use the wwBusiness<T> class as your base and pass the desired generated Entity object as the generic parameter (wws_customersRow in this case):

namespace Westwind.WebStore { public class busCustomer : wwBusiness<wws_customersRow> { public busCustomer() { // *** Preferrably set the connection string from a config store this.ConnectionString = App.Configuration.ConnectionString; // *** Primary mapped table this.Tablename = "wws_customers"; // *** Set new row values to 'blank' values rather than nulls this.NewRowBlankValues = true; // *** Use custom updates rather than DataAdapter this.DataRowUpdateMode = DataRowUpdateModes.OptimizedByPk; // *** Values set here only for reference - these are defaults this.ConnectType = ServerTypes.SqlServer; this.PkField = "Pk"; this.PkType = PkFieldTypes.intType; } } }

This code is identical to the DataRow based version, except that the EntityType is passed as a generic parameter. This enables the Invoice.Entity type to be of the specified generic type.

Using the Business Object Class

Using the generic business object is easy:

public string DataRowBusTest() { busInvoice Customer = new busCustomer(); // *** Load a customer by pk - load DataRow property if (!Customer.Load(1000)) { this.lblErrorMessage.Text = Invoice.ErrorMessage; return false; } // *** Read some values string Company = Invoice.Company; decimal Entered = Invoice.Entered; // *** Update data Customer.Updated = DateTime.Now.Date; if (!Customer.Save()) { this.lblErrorMessage.Text = Customer.ErrorMessage; return false; } // *** Creating a new customer Customer.New(); // *** New Pk value is generated before data is saved int Pk = Customer.Entity.Pk; Customer.Entity.Company = "West Wind"; Customer.Entity.Address = "32 Kaiea"; Customer.Save(); // *** Delete a customer by pk Customer.Delete(Pk); // *** All base wwBusines behavior of course works as well // *** but is unaffected by Entity behavior // *** Execute query and load into TCustomers Table of internal DataSet if (Customer.Execute("select * from " + Customer.Tablename, "TCustomers") = -1) { this.lblErrorMessage.Text = Customer.ErrorMessage; return false; } int Count = Customer.DataSet.Tables["TCustomers"].Rows.Count; return true; }

Note that there are no type conversions in your code and you get full Intellisense as you type your code. The generator also pulls in comments from the database and adds them as XML Comments in the source code so Intellisense should pick up the descriptions as well.

In the above code the Entity is created automatically and without Column binding. You can also create the Entity class directly with a parameterless constructor and then assign the UseColumns property:

wws_customersRow CustRow = new wws_customersRow(); CustRow.UseColumns = true; CustRow.SetDataRow(Customer.DataRow);

Using SetDataRow is also a good idea if you're running operations in a loop, since you can have the column created once then have them reused in subsequent cycles. For example:

Invoice.LoadLineItems(); // *** Creates a DataTable of lineitmes DataTable tbLineItems = Invoice.LineItems.GetDetailTable(); wws_lineitemsRow LineItem = new wws_lineitemsRow(); LineItem.UseColumns = true; foreach (DataRow LineItemRow in tbLineItems.Rows) { LineItem = LineItem.SetDataRow( LineItemRow ); LineItem.Descript = "Item " + x.ToString(); ... more code with the typed lineitem }

Repeated calls to SetDataRow() will reuse the same column definitions created the first time a DataRow is created and so this is more efficient than using string look up names for the DataRow fields.


Entity objects are super easy to use once set up and they make your code more reliable since you get Intellisense and compile time type checking. Making changes to fields also is immediately detetectable by your application as the generated fields that are mismatched with the source code will show up as compiler errors. It's a great way to ensure your database and code stay in sync.


 Last Updated: 12/27/2006 | Send topic feedback