Adapdev Template Projects

DAO Framework

Overview

The DAO Framework provides a well-architected way to access databases. For every table in a database, the following items can be generated:

Table 2. Generated Objects

Object TypeDescriptionTemplate File
Entity ObjectRepresents a table row in the database. This object is focused purely on data storage, and is serializable to allow for distributed applications. This allows for data to be easily transferred between the data tier and business tier (also known as a Transfer Object).\templates\adapdev\cs\entity.tcs, \templates\adapdev\cs\entitybase.tcs
Mock Entity ObjectProvides default test values for a given Entity Object\templates\adapdev\cs\mockentity.tcs
Entity CollectionProvides a strongly-typed collection for the respective Entity Object\templates\adapdev\cs\entitycollection.tcs
Entity Dictionary
Provides a strongly-typed collection for the respective Entity Object
\templates\adapdev\cs\entitydictionary.tcs
Data Access Object
Provides all database operations, such as saving, deleting, updating and retrieving records. The Data Access Object contains numerous features that enhance or wrap existing ADO.NET functionality.
\templates\adapdev\cs\abstractdaobase.tcs, \templates\adapdev\cs\abstractdao.tcs, \templates\adapdev\cs\dbconstants.tcs \templates\adapdev\cs\connectionfactory.tcs
Web Service
Provides DAO functionality via a Web Service
\templates\adapdev\cs\webservice.tcs, \templates\adapdev\cs\webservice.asmx.tcs, \templates\adapdev\cs\webservice.constants.tcs
NUnit Test
Provides a group of tests to verify DAO and Entity Object functionality using the NUnit 2.2 framework.
\templates\adapdev\cs\nunit.tcs, \templates\adapdev\cs\unittest.tcs
NAnt build fileProvides a build file for automatic compilation of all project output. Codus includes a copy of NAnt, in case the target computer doesn't have NAnt installed\templates\adapdev\cs\nant.build
Build utility fileProvides a quick way to launch the NAnt build process. Simply click on the file, and the build will kick off. This alleviates any command line tinkering.\templates\adapdev\cs\runbuild.bat
MS Sql Server Stored ProceduresProvides stored procedures for all DAO functionality\templates\adapdev\cs\storedprocedures.tsql

The most important of these objects is listed below.

Note

For further examples, we recommend looking at the generated NUnit or Zanebug tests.

Architecture

At its most basic, the architecture is composed of one Data Access Object (DAO) and one Entity object per table. The DAO object is a MarshalByRef object, allowing for remote invocation. The Entity object is Serializable, allowing for transfer between remote applications.

Figure 1. DAO Framework Class Diagram (Basic)

DAO Framework Class Diagram (Basic)

Class Diagram

If the full power of the framework is generated, several classes are created addressing different aspects of the architecture. The class diagram below shows the relationship between the various generated classes.

Figure 2. DAO Framework Class Diagram

DAO Framework Class Diagram

Northwind Employees Example

The class diagram below shows a specific implementation for the Northwind Employees table

Figure 3. DAO Framework - Northwind Employees Example

DAO Framework - Northwind Employees Example

Component Diagram

Depending on the options you select, Codus will generate multiple assemblies. Below is the component diagram for a typical project

Figure 4. DAO Framework Component Diagram

DAO Framework Component Diagram

Entity Object

The Entity Object is an object representation of a table row, with some added features.

For every table or view, an Entity will be created in the form of XXXEntity. For example, the Northwind database contains an Employees table. An EmployeesEntity will be created to store information from that table.

Child Properties

If you have foreign keys defined in your database tables, Codus will automatically create child properties in your XXXEntity. For example, the Northwind database contains the Employees table. The Orders table stores the EmployeeId for the Employee that created that order. Since the link from Employee-EmployeeId to Orders-EmployeeId is a foreign key relationship, Codus will automatically create a property called OrdersByEmployeeId

// Retrieve the orders placed by Employee #22
EmployeesDAO dao = new EmployeesDAO();
EmployeeEntity employee = dao.SelectById(22); // SelectOne uses the primary key value as the parameter
foreach(OrdersEntity order in employee.OrdersByEmployeeID)
{
   Console.WriteLine(order.OrderDate); // Display the date of the order
}

Serialization

All Entity Objects are Serializable, which means they can be transferred between remote applications, and/or stored to a file, etc.

The following code shows an example of serializing an Entity Object (using a Northwind database example):

CustomersDAO dao = new CustomersDAO();
CustomersEntity customer = dao.SelectOne("ANTON");

// Serialize using Adapdev.Serialization.Serializer...a utility class.
Console.WriteLine(Adapdev.Serialization.Serializer.SerializeToXml(customer));

This produces the following output:

<?xml version="1.0"?>
<CustomersEntity xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Address>Mataderos  2312</Address>
  <City>Mexico D.F.</City>
  <CompanyName>Antonio Moreno TaquerC-a</CompanyName>
  <ContactName>Antonio Moreno</ContactName>
  <ContactTitle>Owner</ContactTitle>
  <Country>Mexico</Country>
  <CustomerID>ANTON</CustomerID>
  <Phone>(5) 555-3932</Phone>
  <PostalCode>05023</PostalCode>
</CustomersEntity>

ToString

All Entity Objects also override the ToString() method, and will create a string printout of all the objects property names, their object types and values. This is useful for debugging purposes. Below is an example (using a Northwind database):

// Call the ToString method
EmployeesDAO dao = new EmployeesDAO();
EmployeesEntity employee = dao.SelectById(9);
Console.WriteLine(employee);

This produces the following output:

Properties for: EmployeesEntity
	Address(System.String): 7 Houndstooth Rd.
	BirthDate(System.DateTime): 1/27/1966 12:00:00 AM
	City(System.String): London
	Country(System.String): UK
	EmployeeID(System.Int32): 9
	Extension(System.String): 452
	FirstName(System.String): Anne
	HireDate(System.DateTime): 11/15/1994 12:00:00 AM
	HomePhone(System.String): (71) 555-4444
	LastName(System.String): Dodsworth
	Notes(System.String): Anne has a BA degree in English from St. Lawrence College.  She is fluent in French and German.
	Photo(System.Byte[]): System.Byte[]
	PhotoPath(System.String): http://accweb/emmployees/davolio.bmp
	PostalCode(System.String): WG2 7LT
	Region(System.String): 
	ReportsTo(System.Int32): 5
	Title(System.String): Sales Representative
	TitleOfCourtesy(System.String): Ms.

Data Access Object

The bulk of the DAO Framework capability lies in the Data Access Object (DAO). The DAO inherits from the Adapdev.Data.AbstractDAO class, which is part of the free and open-source Adapdev.NET project.

For every table in a database, a corresponding DAO class is generated.

Below are examples of common uses. These examples use code that's generated for the Northwind Employees table:

Retrieving Records

Getting the total number of records in a table

EmployeesDAO dao = new EmployeesDAO();
int count = dao.GetCount();

Getting all records in a table

EmployeesDAO dao = new EmployeesDAO();
List<EmployeesEntity> employees = dao.SelectAll();
foreach(EmployeesEntity e in employees){
   Console.WriteLine(e.FirstName);
}

Getting the top 10 records in a table

EmployeesDAO dao = new EmployeesDAO();
List<EmployeesEntity> employees = dao.SelectAllWithLimit(10);
foreach(EmployeesEntity e in employees){
   Console.WriteLine(e.FirstName);
}

Getting all the records in a table, via a DataSet

// Populate a DataSet
EmployeesDAO dao = new EmployeesDAO();
DataSet employeesDS = dao.SelectAllDataSet();

Getting a specific record

// Retrieve employee record 22
EmployeesDAO dao = new EmployeesDAO();
EmployeeEntity employee = dao.SelectById(22); // SelectById uses the primary key value as the parameter

Getting a DataSet containing a specific record

// Retrieve employee record 22
EmployeesDAO dao = new EmployeesDAO();
DataSet employeeDS = dao.SelectDatasetById(22); // SelectDatasetById uses the primary key value as the parameter

Getting a custom-defined set of records

// Get records using a custom sql statement
EmployeesDAO dao = new EmployeesDAO();
List<EmployeesEntity> al = new List<EmployeesEntity>(dao.Select("SELECT * FROM Employees WHERE FirstName LIKE 'm%'"));

Note

The above example fills all Entity properties, since a SELECT * statement is being executed. If you use a SELECT statement that only grabs specific columns, then only those matching column properties in the Entity object will be filled. The remaining items will remain unfilled.

Getting a custom-defined set of records, via a DataSet

// Get records using a custom sql statement
EmployeesDAO dao = new EmployeesDAO();
DataSet ds = dao.SelectDS("SELECT * FROM Employees WHERE FirstName LIKE 'm%'");

Getting all records with a specified foreign key

// Get records that contain a specified foreign key
// Codus generates SelectAllByXXX methods for each foreign key in a table
EmployeesDAO dao = new EmployeesDAO();
List<EmployeesEntity> al = new List<EmployeesEntity>(dao.SelectAllByReportsTo(2));
foreach(EmployeesEntity employee in al){
   Console.WriteLine(employee.FirstName);
}
Modifying Records

Create a new record

// Create a new record
EmployeesEntity employee = new EmployeesEntity();
employee.FirstName = "Joe";
employee.LastName = "Schmoe";
// ...etc.

EmployeesDAO dao = new EmployeesDAO();
dao.Save(employee);

Note

If you are using an auto-increment column in the database as your primary key, Codus will automatically retrieve the value and update the appropriate object property with the value.

Update an existing record

EmployeesDAO dao = new EmployeesDAO();

// Grab employee 22 and update who they report to
EmployeesEntity employee = dao.SelectOne(22) as EmployeesEntity;
employee.ReportsTo = 5;

dao.Update(employee);

Delete an existing record

EmployeesDAO dao = new EmployeesDAO();
dao.Delete(22); // Delete using the primary key
Transactions

The DAO Framework supports two types of transactions:

Local Transactions

Local transactions allow you to perform transactions on a single database, such as Sql Server. Local transactions are provided via ADO.NET.

To use a local transaction that spans multiple tables or statements, you must create a connection, create a transaction, and then pass the connection and transaction to each action.

// Create the Entity objects
EmployeesEntity employee = new EmployeesEntity();
RegionEntity region = new RegionEntity();
// ...set some values

// Open the db connection and start the transaction
IDbConnection connection = ConnectionFactory.CreateConnection();
connection.Open();
IDbTransaction transaction = connection.BeginTransaction();

// Save the entities to their respective tables using a single transaction
EmployeesDAO employeesDAO = new EmployeesDAO();
RegionDAO regionDAO = new RegionDAO();

// Pass the connection and transaction object through for each operation
employeesDAO.Save(employee, connection, transaction);
regionDAO.Save(region, connection, transaction);

connection.Close();

Distributed Transactions

Distributed transactions allow code to span mutliple platforms in a single transaction. For example, a distributed transaction could do send a message via MSMQ, insert a record into SQL Server and then delete a record from Oracle. If any of these operations fail, the entire transaction will rollback. Distributed transactions are possible via COM+ and System.EnterpriseServices. For transactions, simply use the standard .NET System.Transactions.TransactionScope, which provides you the benefits of distributed transactions but avoids the standard overhead of COM+ (i.e. dynamic registration, strong-named assemblies, etc.)

Important

In order to use distributed transactions, you need to have Windows XP Service Pack 2, Windows 2003, or Windows XP Service Pack 1 with Hotfix 828741.

// Create the Entity objects
EmployeesEntity employee = new EmployeesEntity();
RegionEntity region = new RegionEntity();
// ...set some values

EmployeesDAO employeesDAO = new EmployeesDAO();
RegionDAO regionDAO = new RegionDAO();

// Save them using a distributed transaction
using(TransactionScope transaction = new TransactionScope()){

    employeesDAO.Save(employee);
    regionDAO.Save(region);

    transaction.Complete();
}
Dealing with Connections

By default, each DAO call creates and destroys a database connection. For example:

// Connection is created and destroyed behind the scenes
EmployeesDAO dao = new EmployeesDAO();
dao.Delete(22); // Delete using the primary key

Unfortunately, creating and destroying connections is an expensive operation. If you have a program that is making multiple DAO calls, you're better served using only one open connection. Almost all DAO methods support the ability to pass in an open database connection. Below is an example:

EmployeesDAO dao = new EmployeesDAO();

// The using directive automatically closes the connection.  
// See MS.NET documentation for details.
// If you don't use the "using" directive, then you'll need to explicitly
// open and close the connection.
using(IDbConnection connection = dao.CreateConnection()){
   // open the connection
   connection.Open();

   // get an existing record
   EmployeesEntity employee = dao.SelectOne(8, connection) as EmployeesEntity;
   employee.LastName = "Hilton";

   // update it
   dao.Update(employee, connection);

   // delete another record
   dao.Delete(22);
}

The above example will achieve better performance, since it is only using 1 open connection for all calls, vs. 3 separate connections.

Building Sql Statements

It's not always easy to remember the column names or table names for a database table. To make things easier, each generated DAO class contains constant values for the column names, table name and database name. This makes writing sql statements much easier. The following items are generated:

Table 3. Constants

COLUMN_XXXProvides access to the name of the XXX field
DATABASE_NAMEProvides access to the name of the database that this table is contained in
TABLE_NAMEProvides access to the name of the table
TABLE_PRIMARYKEYIf the table has a primary key, then this provides access to the name of the primary key field

Below is an example for using these constants:

string sql = String.Format("SELECT {0}, {1}, {2} FROM {3} WHERE {4} LIKE 'm%'",
							EmployeesDAO.COLUMN_FIRSTNAME,
							EmployeesDAO.COLUMN_LASTNAME,
							EmployeesDAO.COLUMN_EMPLOYEEID,
							EmployeesDAO.TABLE_NAME,
							EmployeesDAO.COLUMN_FIRSTNAME);

Note

If the column name contains a space - for example First Name - then you'll need to surround the column name with [ ]. For example:

string sql = String.Format("SELECT [{0}] FROM {3} WHERE [{4}] LIKE 'm%'",
							EmployeesDAO.COLUMN_FIRSTNAME,
							EmployeesDAO.TABLE_NAME,
							EmployeesDAO.COLUMN_FIRSTNAME);

In the example above, you'll note that [ ] has been added. The resulting statement would be:

SELECT [First Name] FROM Employees WHERE [First Name] LIKE 'm%'
Executing Statements

Beyond the capabilities listed above for selecting records, etc., the DAO Framework has built in support for executing custom statements that don't return anything.

EmployeesDAO dao = new EmployeesDAO();
dao.ExecuteNonQuery("UPDATE FirstName SET FirstName = 'John' WHERE EmployeeID = 5");
Adding Custom Code

The DAO Framework generates two classes:

  • XXXDAOBase

    This class contains the core functionality. Modifications can occur here, but it is not recommended that custom code be added, since this file is overwritten by the Codus engine each time generation takes place.

  • XXXDAO

    This class inherits from XXXDAOBase. The Codus engine will not overwrite this file upon subsequent generations, so it is recommended that all custom code be placed here.

    Warning

    The behavior of file overwriting differs between straight generation and generation to VS.NET 2003. In straight generation (i.e. simply generating to an output directory), the XXXDAOBase will be overwritten each time, whereas the XXXDAO file is only created once, and not overwritten.

    In the case of VS.NET 2003, all code is generated to an output directory and then copied over to a VS.NET 2003 solution directory. If your custom code is in the XXXDAO within the output directory, it will be preserved. However, if you've made changes within VS.NET and then regenerate into the same solution, your changes could be lost. Please be careful when dealing with VS.NET generation so that you don't lose your custom code.

Building the Framework

VS.NET 2005

The DAO Framework allows for generation directly into VS.NET 2005. Since the DAO Framework can generate hundreds of files, it is recommended that you use this capability.

NAnt

You can select NAnt generation, and a .build file will be placed in the output directory. You can launch the build by clicking on the runbuild.bat in the output directory, which will launch NAnt and build the generated output.

Manual

If you choose not to NAnt or VS.NET 2005, all of the binaries necessary are located in the [Codus Install Location]\shared directory. Here are the necessary references:

  • All Projects

    • \adapdev\Adapdev.dll

    • \adapdev\Adapdev.Data.dll

  • NUnit Tests

    • nunit229\nunit.framework.dll

    • [output directory]\dao.dll

  • Web Services

    • [output directory]\dao.dll

Modifying the Framework

The framework uses the Velocity template language for all code generation, provided via modified version of NVelocity. The following options are available for making modifications:

  1. Modify the included templates - unfortunately, the internals of these templates are not currently documented.

  2. Download the free Adapdev.NET project - much of the code used in this project is built on top of Adapdev.NET. This is where you'll find the AbstractDAO class that all generated XXXDAO classes are based on

NHibernate Framework

Overview

The nHibernate templates provide an easy way to generate all classes, mappings, tests and configuration information for a specific database. This gives you the power of nHibernate, but removes a lot of the tedious coding tasks that are normally involved. By generating nHibernate code via Codus, you can save a substantial amount of time.

Below is an overview of the major object types, their description and associated template files.

Table 4. Generated Objects

Object TypeDescriptionTemplate File
Entity ObjectRepresents a table row in the database. This object is focused purely on data storage, and is serializable to allow for distributed applications. This allows for data to be easily transferred between the data tier and business tier (also known as a Transfer Object).\templates\nhibernate\entity.tcs
Entity Mapping FileProvides the nHibernate mappings between an entity and a database table. One hbm is generated per Entity.\templates\nhibernate\hbm.xml
Mock Entity ObjectProvides default test values for a given Entity Object\templates\nhibernate\mockentity.tcs
Entity CollectionProvides a strongly-typed collection for the respective Entity Object\templates\nhibernate\entitycollection.tcs
Entity Dictionary
Provides a strongly-typed collection for the respective Entity Object
\templates\nhibernate\entitydictionary.tcs
Data Access Object
Wraps the nHibernate API to provide database operations.
\templates\nhibernate\dao.tcs
ConfiguratorLoads all configuration information for nHibernate and creates the ISessionFactory\template\nhibernate\configurator.tcs
Hibernate Configuration FileProvides nHibernate specific configuration\template\nhibernate\hibernate.cfg.xml
NUnit Test
Provides a group of tests to verify DAO and Entity Object functionality using the NUnit 2.2 framework.
\templates\nhibernate\nunit.tcs, \templates\nhibernate\unittest.tcs
NAnt build fileProvides a build file for automatic compilation of all project output. Codus includes a copy of NAnt, in case the target computer doesn't have NAnt installed\templates\nhibernate\nant.build
Build utility fileProvides a quick way to launch the NAnt build process. Simply click on the file, and the build will kick off. This alleviates any command line tinkering.\templates\nhibernate\runbuild.bat

Entity Object

The Entity Object is an object representation of a table row, with some added features.

For every table or view, an Entity will be created in the form of XXXEntity. For example, the Northwind database contains an Employees table. An EmployeesEntity will be created to store information from that table.

NHibernate Mapping File

For every XXXEntity object, an XXX.hbm.xml file is generated that contains the table to XXXEntity mappings.

Serialization

All Entity Objects are Serializable, which means they can be transferred between remote applications, and/or stored to a file, etc.

The following code shows an example of serializing an Entity Object (using a Northwind database example):

CustomersDAO dao = new CustomersDAO();
CustomersEntity customer = dao.SelectById("ANTON");

// Serialize using Adapdev.Serialization.Serializer...a utility class.
Console.WriteLine(Adapdev.Serialization.Serializer.SerializeToXml(customer));

This produces the following output:

<?xml version="1.0"?>
<CustomersEntity xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Address>Mataderos  2312</Address>
  <City>Mexico D.F.</City>
  <CompanyName>Antonio Moreno TaquerC-a</CompanyName>
  <ContactName>Antonio Moreno</ContactName>
  <ContactTitle>Owner</ContactTitle>
  <Country>Mexico</Country>
  <CustomerID>ANTON</CustomerID>
  <Phone>(5) 555-3932</Phone>
  <PostalCode>05023</PostalCode>
</CustomersEntity>

Data Access Object

For every table, a DAO object is generated. This object encapsulates the nHibernate details to simplify things, but also exposes the nHibernate ISession if you want to use it directly.

The DAO object contains methods for selecting all records, selecting records by primary key, and selecting records by foreign key.

Retrieving Records

Retrieving records is straight forward.

Selecting All Records

// Instantiate the DAO for the Northwind Employees table
EmployeesDAO dao = new EmployeesDAO();

// Returns all records stored in the Northwind Employees table
IList employees = dao.SelectAll();

// Iterate through each item and write it to the Console
foreach(EmployeesEntity employee in employees){
  Console.WriteLine(employee);
}

Selecting a Specific Record

// Instantiate the DAO for the Northwind Employees table
EmployeesDAO dao = new EmployeesDAO();

// Return Employee #2
EmployeesEntity employee = dao.SelectById(2);

// Write it to the console
Console.WriteLine(employee);

Selecting Specific Records by Foreign Key

// Instantiate the DAO for the Northwind Employees table
EmployeesDAO dao = new EmployeesDAO();

// Returns all employees that report to Employee #2.
IList employees = dao.SelectAllByReportsTo(2);

// Iterate through each item and write it to the Console
foreach(EmployeesEntity employee in employees){
  Console.WriteLine(employee);
}

Getting the Total Number of Records

// Instantiate the DAO for the Northwind Employees table
EmployeesDAO dao = new EmployeesDAO();

// Get the total number of records for the Employees table
int count = dao.Count;

Custom Queries

The DAO object exposes the underlying nHibernate API. Below is an example of a custom query using the nHibernate API directly. Please see nHibernate documentation for guidance on custom queries.

// Instantiate the DAO for the Northwind Employees table
EmployeesDAO dao = new EmployeesDAO();

// Get the total number of records for the Employees table using the nHibernate API
int count = 0;
ISession session = dao.ISessionFactory.OpenSession();
IList results = session.Find("select count(o.EmployeeID) from Test.EmployeesEntity as o");
if(results[0] != null) count = (int)results[0];
session.Close();
Modifying Records

Modifying records is done easily via the Save and Delete methods.

Creating a new record

EmployeesDAO dao = new EmployeesDAO();

EmployeesEntity employee = new EmployeesEntity();
employee.FirstName = "John";
employee.LastName = "Doe";
// ... set the rest of the values

// Save the record
dao.Save(employee);

Editing an existing record

EmployeesDAO dao = new EmployeesDAO();

// Get employee #2
EmployeesEntity employee = dao.SelectById(2);

// Edit some values
employee.FirstName = "John";
employee.LastName = "Doe";

// Update the record
dao.Save(employee);

Deleting a record

EmployeesDAO dao = new EmployeesDAO();

// Get employee #2
EmployeesEntity employee = dao.SelectById(2);

// Delete the record
dao.Delete(employee);