Outputting Code - Examining Code Generation Mechanics
(Page 5 of 19 )
Now that you’ve seen an overview of the harness you’ll use to run code generation, you’ll take a close look at the templates that output code. Regardless of the mechanism you’re using, I call what holds your code pattern a template. When you’re using brute-force or CodeDOM generation, the template is a .NET method; when you’re using XSLT code generation, the template is an XSLT stylesheet.
The following sections look at how you work with the templates in each of the three techniques for generating code. I approach each technique differently because the core mechanism differs. In XSLT code generation, I leave the XSLT basics for Appendix A and explore how to take sample code and convert it to an XSLT template. The section “Exploring Details of Brute-Force Generation” is slim because the beauty of this technique is that it’s simple and uses techniques that are probably already familiar to you. Working with the CodeDOM is complex, and although that section just flutters across the surface, that section is long, complex, and won’t be relevant to all readers. There’s just so little information on using the CodeDOM available today that the section seemed necessary for those readers who will use, make a decision on using, or simply want to understand the CodeDOM. Appendix D has additional details on issues you may encounter if you work with the CodeDOM.
NOTE: You may find creative ways to combine these approaches, such as your own tokenizing scheme. I keep the approaches separate to show the fundamentals of each. You can pull from each if you’ve devised a hybrid approach. I’m not a fan of tokenizing schemes because they don’t have the power of XSLT, so they’re hard to use in complex code scenarios. |
Introducing the Target and Metadata Files
Metadata files are an XML description of your application’s data. Target files are sample source code files that look like what you want to generate. You’ll build templates that output code files that match your target file using XML metadata as input. You’ll compare the output with the target as an initial test of your templates.
For reference, Listing 3-1 shows part of the XML input file used in this chap-ter’s XSLT and brute-force code generation examples. This XML describes a single data table and is part of a larger metadata file containing descriptions for each table, stored procedure, view, function, and user-defined data type in the database. I removed privilege information and replaced the details of most columns with ellipses to shorten the listing. The Table element and each TableColumn element contain many attributes. These attributes provide details about the table or column you’ll use during code generation.
Listing 3-1. Part of the XML Input File Used in This Chapter
<dbs:Table Name="Customers" OriginalName="Customers" SingularName="Customer"
PluralName="Customers" DisplayName="CompanyName" Caption="Customer"
DeletePriority="" InsertPriority="0">
<dbs:TableColumns>
<dbs:TableColumn Name="CustomerID" OriginalName="CustomerID"
Ordinal="1" Default="" AllowNulls="false" SQLType="NChar"
NETType="System.String" MaxLength="5" IsPrimaryKey="true"
Caption="ID" RegEx="AlphaNumericPunc"/>
<dbs:TableColumn Name="CompanyName" OriginalName="CompanyName" Ordinal="2"
Default="" AllowNulls="false" SQLType="NVarChar"
NETType="System.String" MaxLength="40" IsPrimaryKey="false"
Caption="Company"
Desc="Company Name for shipping labels and correspondence"
RegEx="AlphaNumericPunc" />
<dbs:TableColumn Name="ContactName" OriginalName="ContactName" Ordinal="3"
Default="" AllowNulls="true" SQLType="NVarChar"
NETType="System.String" MaxLength="30" IsPrimaryKey="false"
Caption="Contact" RegEx="AlphaNumericPunc" />
...
</dbs:TableColumns>
<dbs:TableConstraints>
<dbs:PrimaryKey>
<dbs:PKField Name="CustomerID" Ordinal="1" />
</dbs:PrimaryKey>
<dbs:TableRelations>
<dbs:ChildTables>
<dbs:ChildTable Name="Orders">
<dbs:ChildKeyField Name="CustomerID"
Ordinal="1" />
</dbs:ChildTable>
<dbs:ChildTable Name="CustomerCustomerDemo">
<dbs:ChildKeyField Name="CustomerID"
Ordinal="1" />
</dbs:ChildTable>
</dbs:ChildTables>
</dbs:TableRelations>
</dbs:TableConstraints>
<dbs:ExtendedProperties>
<dbs:ExtendedProperty Name="Desc"
Value="Contains customer address and contact information" />
</dbs:ExtendedProperties>
</dbs:Table>
Listing 3-2 shows portions of the target code file generated from the meta-data shown in Listing 3-1. Ellipses indicate where I clipped redundant sections. I purposely showed only two columns. You can see the rest in the download or mentally extrapolate.
NOTE: This sample contains both a class for the collection and the individual objects in the same file to illustrate more code generation techniques. You can include related classes in the same file, or you can create a separate file for each class when you generate code as shown in Chapter 8. This sample is deliberately different from the example in Chapter 8. This gives you template examples that create a greater variety of output code. |
Listing 3-2. The Target File Used to Create Templates for All Three Code Generation Types
Option Strict On
Option Explicit On
Imports System
Imports KADGEN
Imports System.Data
#Region "Description"
' Orders.vb
#End Region
Public Class OrderCollection
Inherits CollectionBase
#Region "Constructors"
Protected Sub New()
MyBase.New("OrderCollection")
End Sub
#End Region
#Region "Public and Friend Properties, Methods and Events"
Public Overloads Sub Fill( _
ByVal OrderID As System.Int32, _
ByVal UserID As Int32)
OrderDataAccessor.Fill(Me, OrderID, UserID)
End Sub
#End Region
End Class
Public Class Order
Inherits RowBase
#Region "Class Level Declarations"
Protected mCollection As OrderCollection
Private Shared mNextPrimaryKey As int32 = -1
Private mOrderID As System.Int32
Private mCustomerID As System.String
...
#End Region
#Region "Constructors"
Friend Sub New(ByVal OrderCollection As OrderCollection)
MyBase.new()
mCollection = OrderCollection
End Sub
#End Region
#Region "Base Class Implementation"
Friend Sub SetNewPrimaryKey()
OrderID = mNextPrimaryKey
mNextPrimaryKey -= 1
End Sub
#End Region
#Region "Field access properties"
Public Function OrderIDColumnInfo As ColumnInfo
Dim columnInfo As New ColumnInfo
columnInfo.FieldName = "OrderID"
columnInfo.FieldType = gettype(System.Int32)
columnInfo.SQLType = "int"
columnInfo.Caption = "" columnInfo.Desc = ""
End Function
Public Property OrderID As System.Int32
Get
Return mOrderID
End Get
Set(ByVal Value As System.Int32)
mOrderID = Value
End Set
End Property
Public Function CustomerIDColumnInfo As ColumnInfo
Dim columnInfo As New ColumnInfo
columnInfo.FieldName = "CustomerID"
columnInfo.FieldType = gettype(System.String)
columnInfo.SQLType = "nchar"
columnInfo.Caption = "" columnInfo.Desc = ""
End Function
Public Property CustomerID As System.String
Get
Return mCustomerID
End Get
Set(ByVal Value As System.String)
mCustomerID = Value
End Set
End Property
...
#End Region
End Class
The following sections show how to create this file via XSLT and brute-force code generation. These example will show how to output Visual Basic .NET (VB .NET) code. The Apress Web site includes parallel examples that output the code in C# files. Chapters 4 and 6 have examples outputting Structure Query Language (SQL) stored procedures.
This chapter is from Code Generation in Microsoft .NET by Kathleen Dollard (Apress, 2004, ISBN: 1590591372). Check it out at your favorite bookstore today.
Buy this book now. |
Next: Exploring Details of XSLT Code Generation >>
More .NET Articles
More By Apress Publishing