The EntityGenerator Tool and Entity Objects

This tool is used to generate Entity classes for the business objects of the Web Store application or any database in general. You can run this tool against a database and it will create one class each for each table in the database creating simple entity classes.

Because the Entity classes are generated you have to use this tool any time changes are made to the database that add or remove fields or change field types. The tool is easy to use and remembers its settings. You set it up once and write an output file and then simply reload this output file to remember the previous settings so re-generation is quick and easy.

Here's what the tool looks like:

The following properties are available:

ConnectionString
The most important property: The connection string to the database to build Entity objects on.

Tables
The tables you want to generate Entities for. If empty all tables are generated. There's a UI editor that lets you select tables individually.

GenerateDataContract
Determines whether a WPF DataContract will be generated for each class. When doing so you can use these entity classes as WPF message objects in a [DataContract].

GenerateIPropertyChangedEvents
If true generates IPropertyChanged code for each property set method. The generated class always implements IPropertyChanged, but this flag actually enables the abillity fire the required notification events.

Namespace
This is the namespace of the class that is generated. This should point at your applications namespace most likely. For example, Westwind.WebStore.

OutputFile
The output file where the output is written to. This is a CSharp source code file and the file contains an embedded configuration section that contains these settings in a serialized format. This allows the file to be opened with these settings intact.

wwDataRowContainerNameSpace
This is the namespace where the wwDataRowContainer class is defined - typically this is Westwind.Business objects. You can also leave this value blank in which case the generated source file will include a generated wwDataRowContainer class that becomes the base for the entity objects.

DefaultDateValue, DefaultStringValue
These are the default values that are assigned to Date and string values. These values are literal values that get assigned so just use an expression. Example: App.APP_MINDATE or DateTime.MinDate, or "" or string.Empty are all valid values.

EntityClassPostFix
An optional value that can be appended to the classname. So if the tablename is invoice and you specify Entity, then the name of the class becomes invoiceEntity. Alternately leave this value blank and get just the tablename. For example in the Web Store all Entity classes end in Row so names of classes are wws_CustomersRow.

TablePrefix
If a prefix is provided the table parser looks only for tables that start with the provided prefix.

StripTablePrefixForClass
If you chose a prefix you can optionally choose to strip the prefix for generated classes. So if the table is wws_Customers and you have a prefix of wws_ and StipTablePrefixForClass=true you'll get Customers as the class name.

UseProperCaseForClasses
Determines if class names are made proper. Useful if your table names are all lower case and you want proper case for classes. If you have a table named mytable it will become a class name of Mytable when this value is true. Otherwise the same casing as the database is used.

UseProperCaseForProperties
Determines if property names are made proper. Useful if your property names are all lower case and you want proper case. Same as with the table if true the first character is capitalized. Otherwise the exact name in the database is used.

GenerateDataContract
If true generates a WCF [DataContract] for the class and [DataMember] attributes for each of the properties generated so the Entity effectively becomes a properly formatted WCF message object. Adds the appropriate WCF namespaces so this requires that you reference the appropriate WCF assemblies.


Important:
This tool is a code generator, so you will need to re-generate whenever the database changes. However, this is a one step process (unlike the DataSet generators in VS.Net) as it generates everything directly off your Database.


Once the file has been generated it contains the configuration information that was used to generated. You can re-open the file with the EntityGenerator.exe tool and reload the existing settings so regeneration should be quick and easy.

Tip: Add EntityGenerator as an Open With.. VS Tool
It's likely you'll need to regenerate the Entities eventually and an easy way to do this is by adding the EntityGenerator as an option on the Open With... dialog. To do this, right click on the generated .cs file in your project and click Open With. Select Add and then find the EntityGeneratorTool and select it. Now it shows up on the list of Open With tools for any file and you can simply point it at an existing generated file:

When the file is loaded it will automatically read the last settings from the generated source file.

What gets generated

This tool generates one class per database table you select (or all of them). If you're using wwBusiness, the generated classes are based of the Westwind.BusinessObjects.wwDataRowContainer class. You can also optionally have the generator generate this class directly into the source file if you want to use the tool independently of the West Wind framework. In that case leave the wwDataRowContainer Namespace property blank which instructs the generator to create the class.

The generated code looks something like this:

// // *** Auto Generated Code by DataRowContainerGenerator // *** Created by West Wind Technologies, http://www.west-wind.com // *** // *** Generated on: 7/11/2006 8:58:07 PM // using System; using System.Data; using System.Collections; using System.Reflection; using System.Xml.Serialization; using Westwind.BusinessObjects; namespace Westwind.WebStore { [Serializable] public partial class wws_customersRow : wwDataRowContainer { public wws_customersRow() : base() {} public wws_customersRow(DataRow Row) : base(Row) {} /// <summary> /// Primary Key /// </summary> public Int32 Pk { get { if (this.DataRow == null) return this._Pk; if (this.UseColumns) { if (this.DataRow.IsNull(this.PkColumn) ) return 0; return (Int32) this.DataRow[this.PkColumn]; } else { if (this.DataRow.IsNull("pk") ) return 0; return (Int32) this.DataRow["pk"]; } } set { if (DataRow != null) this.DataRow["pk"] = value; this._Pk = value; } } private Int32 _Pk; /// <summary> /// Last name of the customer /// </summary> public String Lastname { get { if (this.DataRow == null) return this._Lastname; if (this.UseColumns) { if (this.DataRow.IsNull(this.LastnameColumn) ) return null; return (String) this.DataRow[this.LastnameColumn]; } else { if (this.DataRow.IsNull("lastname") ) return null; return (String) this.DataRow["lastname"]; } } set { if (DataRow != null) this.DataRow["lastname"] = value; this._Lastname = value; } } private String _Lastname; /// <summary> /// Date of the Last Order placed. /// </summary> public DateTime Lastorder { get { if (this.DataRow == null) return this._Lastorder; if (this.UseColumns) { if (this.DataRow.IsNull(this.LastorderColumn) ) return DateTime.MinValue; return (DateTime) this.DataRow[this.LastorderColumn]; } else { if (this.DataRow.IsNull("lastorder") ) return DateTime.MinValue; return (DateTime) this.DataRow["lastorder"]; } } set { if (DataRow != null) this.DataRow["lastorder"] = value; this._Lastorder = value; } } private DateTime _Lastorder; // ... More fields // *** Column Definitions DataColumn PkColumn; DataColumn LastnameColumn; DataColumn LastorderColumn; / protected override void CreateColumns() { PkColumn = this.DataRow.Table.Columns["Pk"]; LastnameColumn = this.DataRow.Table.Columns["Lastname"]; LastorderColumn = this.DataRow.Table.Columns["Lastorder"]; // ... more column init this.ColumnsCreated = true; } } // ... more tables }

You can see that each property is backed by a field and logic runs that first checks to see if a DataRow is loaded and if so retrieves the values from the DataRow. If not the value is retrieved from the property. Set operations always set the property to give the object real state that can be persisted using standard .NET serialization for remoting, WCF, serialization etc.

For DataRow access there are two modes: UseColumns can be set to true or false. Using Columns creates a DataColumn object for each field which can be more efficient when retrieving column values, but there's some overhead in creating the columns in the first place. When columns are not retrieved the data is simply returned using the FieldName index. Otherwise the Column itself is used for an index.

Another advantage of not forcing use of columns is that you can assign DataRows that have only partial field data - so if you run a query like select Company,Pk you can safely use the Entity.Company and Entity.Pk fields of the Entity even though all the rest of the fields are missing. However, be careful - access to the missing fields in the table will cause runtime errors! It's a tradeoff but it gives you a lot more flexibility in accessing 'dynamic' query data through strongly typed objects.

Using Columns makes sense if you retrieve a lot of fields, such as when going through multiple rows of data. Otherwise using the string indexes probably provides better performance. In either case you get a typed interface to the DataRow. If no DataRow is loaded into an entity, the Field values are used to return values.

In the West Wind business framework the Entity object (and its underlying DataRow) are automatically loaded when you call the Load(), New(), GetBlankRecord() methods.

The class has a SetDataRow() method which can be used to assign an arbitrary DataRow to the the object. As long as the DataRow has matching fields that match the properties it can be accessed once loaded.



 Last Updated: 3/7/2007 | Send topic feedback