| West Wind Web Store .NET 2.0 |
wwBusiness<T>: Entity based Business Objects
|
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:
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.

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.
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.
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