Introduction
If you are new to n-tier architecture this tool will give you a helping hand to understand what you are building. If you are an old hand at n-tier then I'm not telling you anything new when I say that building all those foundational tiers by hand can be tedious.
If you take a look at the source code you will see that I am simply using a brute force method to write the required code out to the stipulated files and folders. Feel free to improve the code and share it with everyone else.
Background
The power and flexibility that a system architectured with multiple layers provides is something I just can not do without. Business systems are becoming more complex, users demand friendly ways of doing multi-stepped procedures, and business rules always change. I needed a tool that would allow me to reduce the amount of tedious coding that comes with building these foundational layers, but I also wanted to be able to change any code anywhere without having to re-write large portions.
The Code
The code is broken into five sections:
- Control behavior
- BE code
- BLL code
- DAL code
- UI code
Each section follows the same process:
- Get the entered Namespace, folder and class information from the controls
- Assign appropriate data types
- Write the code to the specified folder
Each project layer is created in the same manner. This is the code that creates the BE layer.
StreamWriter sw = File.CreateText(txtConstants.Text.Trim() + className + ".cs");
sw.WriteLine("using System;");
sw.WriteLine("");
sw.WriteLine("namespace " + txtBENamespace.Text.Trim() + ".Constants");
sw.WriteLine("{");
sw.WriteLine(" public enum " + className + "Fields");
sw.WriteLine(" {");
fCount = 1;
foreach (PropertyMap field in fieldList)
{
if (fCount > 1)
sw.Write(", " + field.Name);
else
sw.Write(" " + field.Name);
fCount++;
}
sw.WriteLine("");
sw.WriteLine(" }");
sw.WriteLine("}");
sw.Close();
sw.Dispose();
The PropertyMap
class holds the attributes of each field in the database table along with the control type assigned to it and the name given to the control. This class is identical in format to the class being written in the BE layer.
Using the tool
Download the compiled utility, either from here or my website. My website (http://veracitysystems.com/downloads/public) will always have the latest version of the code.
Create a new empty solution in Visual Studio, and then create an empty project for each of the layers.
Run the tool, and let it create the code in the folders for each layer. Click the "Show all files" button in the solution explorer and include the new files in your project.
Secondly, if you want to understand how it all works, then download the source. Once again, the latest copy of the source is on my website.
There are a number of comments and assumptions I have made which will be pertinent to newbie n-tier designers, so if you are an experienced coder, you can ignore the rest of this section.
The tool will create the following tiers:
- Business Entities (also known as Business Objects) which I will refer to as the BE layer. These are very light weight, extremely small and fast.
- Business Logic Layer (also known as Business Rules) which I will refer to as the BLL layer. These too, are small and efficient, and this is where you can place your own business logic.
- Data Access Objects which I will refer to as the DAL layer. The workhorse of the foundation layers, these classes communicate to your database/s on behalf of your application.
- User Interface which I will refer to as the UI.
There are, of course other layers, two in particular I use all the time. They are Presentation Entities/Objects (PE) and Presentation Logic (PL). The tool does not currently address these latter two, but what it does create is enough to get you well on the way to enjoying the benefits of n-tier.
The following assumptions and results apply:
- The tool only produces C# code. There is no VB alternative.
- The tool assumes every database table has a Primary Key (PK) set on a single field.
- The tool assumes database table names are in the singular form. (Plurals are OK, but you will need to make a small manual change to the DAL code prior to compiling).
- The tool only deals with the most common data types. If you are using any of the new data types introduced in SQL 2012 (spatial, etc) then you will need to add these to the source code yourself (or wait until I get around to needing them).
- The tool will create code that will ensure you never suffer from a SQL injection attack ever again. All commands sent to the database are parametrized.
- All appropriate methods created are available in your Intellisense lists.
- All code conforms to Microsoft's coding conventions. (Refer here and here).
The BE code
The first project created by the tool is the Business Entities layer.
Enums
The tool will create a set of enums that you can use to refer to fields, and importantly, pass them as parameters.
AdoDotNetDataProvider
The AdoDotNetDataProvider
class handles the common data providers:
You can, of course, add your own (Oracle, etc.)
The BLL code
The BLL classes mimic their DAL siblings, and maybe that is all you need to do. However, if you have business logic code that is used in more than once place, this is the layer to put it in.
The DAL code
The DAL does not handle any Stored Procedures. If you think about it, SPs hold business logic, and that belongs in the BLL. I know there are a million reasons why SPs are a good thing, and I don't want to get into another argument about the "righteous" way of coding; suffice to say this tool does not support SPs.
Here is the SelectByID()
method. It returns a single object of the class type.
swDAL.WriteLine(" public static BE SelectById(Int32 id)");
swDAL.WriteLine(" {");
swDAL.WriteLine(" BE result = new BE();");
swDAL.WriteLine(" using (IDbConnection connection = DataConnection.Connection())");
swDAL.WriteLine(" {");
swDAL.WriteLine(" String sqlQuery = String.Format(\"SELECT * FROM {0} WHERE {1}=@" +
key + "\", _tableName, _" + key + ");");
swDAL.WriteLine(" IDbCommand command = DataConnection.Command(connection, sqlQuery);");
swDAL.WriteLine(" AddParameter(command, \"" + key + "\", id );");
swDAL.WriteLine(" connection.Open();");
swDAL.WriteLine(" IDataReader reader = command.ExecuteReader();");
swDAL.WriteLine(" while (reader.Read())");
swDAL.WriteLine(" {");
swDAL.WriteLine(" result = ToObject(reader);");
swDAL.WriteLine(" }");
swDAL.WriteLine(" }");
swDAL.WriteLine(" if (result." + key + " > 0)");
swDAL.WriteLine(" {");
swDAL.WriteLine(" return LoadObject(result);");
swDAL.WriteLine(" }");
swDAL.WriteLine(" else");
swDAL.WriteLine(" {");
swDAL.WriteLine(" return null;");
swDAL.WriteLine(" }");
swDAL.WriteLine(" }");
swDAL.WriteLine(" #endregion");
swDAL.WriteLine("");
Some things to note about this code:
Each method always returns either an object of the same class, or a list of those same objects. IOW, in the DAL for our customer class,
each method returns an object of type "customer", or a list of customer objects.
The call to the ToObject()
method returns a single instance of the class object. The LoadObject()
method simply casts
our object into the data type of the class we are using.
You will see a couple of methods that probably need a brief explanation:
DataAccessObject Class
The DataAccessObject
holds methods that handle the parametrization of our database calls and the conversion of one data type
to another (e.g.: Image to Byte Array and back again).
DataConnection Class
The DataConnection
classes holds methods that handle our connection strings and data providers and links to our AdoDotNetDataProvider
defined in the BE layer.
A word about the UI code
The current version of the tool produces UI code assuming you are using the DevExpress suite of controls for WinForms.
If enough people request it, I will add support for the standard Microsoft controls that are native to Visual Studio. The BE/BLL/DAL code produced
by the tool can be used in all types of applications; it is only the UI code that is WinForm specific.
Wiring it all up
Before you start, create a folder where you want your Visual Studio solution to reside. Run the ORM Tool executable placing the results
for each layer in its own project which will reside in its own folder, inside your solution folder. (The tool will prompt you for this automatically.)
Establish the connecting references in each project as follows:
- In the BLL project, add references to the BE and DAL projects.
- In the DAL project. add a reference to the BE project.
- In your UI project, add a reference to the BE and BLL projects.
Compile each project, and you should be right to start creating your GUI forms. If you have the DevExpress WinForms library, you can tick
to create the UI layer as well, and the tool will create browse and CRUD forms for each class in the BE layer.
As mentioned before, if you are using plurals in the database table names you will need to make a small change in each table's DAL.
private static String _tableName = "Customers";
One other thing you might like to try. Rather than choosing a database table you can select a text file that contains the field specifications
of the table you want to use. If you have multiples text files, one for each table. Place them in a folder outside your solution structure,
and leave the class name empty. The tool will know to open each text file in succession and build a BE/BLL/DAL/UI set of classes for each.
Future Functionality
One of the things you will notice is that you can only build the code for a single database table at a time. Sure, you can repeat the steps
for each table in the database, like I do right now, but I think it would be helpful if I added a little code that allowed you to point the tool
at a database, and it would build the code for every table it found. I am not sure when I will get around to this, as work always has a way
for interrupting the good things in life, but send me a request if this is something you will use.
History
While we have been using this tool for over 3 years, this is the first release into the "wild".