ZenArchitect.NL (Henk van Dijken)
the art of model-driven code generation
the art of model-driven code generation
Jul 29th
After Generating Database Objects from an UML Model you are desperately in need of a data access layer (DAL) and a business logic layer (BLL). Today we are going to generate the famous Business Entities.
After executing that funny sql-script we generated from UML previously, you are the proud owner of a database. Since I am a great fan of MyGeneration we will use a similar approach and scrape the meta model from the database.
To be able to do so, the code generator needs some input. First, it has to know which tables must be read (filter) and where to find the tables (database) to extract meta data from.
At this point the generator has enough information to read the data model and generate code. The list of tables are traversed and classes are created. Within each table the meta data of its columns are extracted.
Since we – at this moment – are not able to automagically convert data types, we also need a support routine for conversion of database type to its C#.NET equivalent. This is done by append some script to the template.
Finally, using this template, the following code is generated from the selected data model.
/*------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// ZaosGenerator Version: 1.0.0.0
// Template Author : Henk van Dijken
// Generation Date : 29-7-2010 21:12:15
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//----------------------------------------------------------------------------*/
using System;
using System.Collections.Generic;
using System.Text;
namespace ZenArchitect2.BusinessEntities
{
public partial class TestParent
{
public TestParent() {}
private int TestParentIDField;
public int TestParentID
{
get { return this.TestParentIDField; }
set { this.TestParentIDField = value; }
}
private string TestParentName1Field;
public varchar TestParentName1
{
get { return this.TestParentName1Field; }
set { this.TestParentName1Field = value; }
}
private int TestParentNumberField;
public int TestParentNumber
{
get { return this.TestParentNumberField; }
set { this.TestParentNumberField = value; }
}
}
public partial class TestChild
{
public TestChild() {}
private int TestChildIDField;
public int TestChildID
{
get { return this.TestChildIDField; }
set { this.TestChildIDField = value; }
}
private int TestParentIDField;
public int TestParentID
{
get { return this.TestParentIDField; }
set { this.TestParentIDField = value; }
}
private string TestChildNameField;
public varchar TestChildName
{
get { return this.TestChildNameField; }
set { this.TestChildNameField = value; }
}
}
}
Jul 26th
I am very proud to announce that I fixed my site/blog its redirecting mechanism, so that you can find me again via Google.
Jun 30th
Sorry, my blog is temporarily unavailable. It is under (re)construction towards blog 4.0.
Or, to be more honest. I screwed up, again.
1-2-3. See, there it is again. Now I only have to find/reconstruct my pictures.
Yes! I found them again. There they are. So, another happy blogger is on line.
But wait, this is an excellent opportunity to refactor some stuff. Good idea. I’ll do that.
So, meanwhile apologies for the inconvenience.
I’ll promise that next time I’ll try to backup first before doing a restore, instead of the other way around.
Jun 26th
In previous
posts I wrote about validation AOP-style, using Policy Injection or Depency Injection (Unity). I am a true believer that this form of validation is the way to go.
That said, what kind of validation do you really need?
User Input Validation is probably the first thing that pops up into your mind, and that is indeed an important one. But, in fact, validation can be applied to almost every layer. That’s why they call it a cross cutting concern and AOP makes sense.
That’s not what I mean. I am talking about using validators here. You probably know the available ASP.NET validators, like shown in above picture.
But you know what? Although User Input Validation is important, sooner or later the data will be persisted to a database. And if your database accepts varchar(10) only, then “Thunderbird” is not such a good idea to type.
In short, you are in need of a StringLengthValidator.
Of course you can create you own simple validation rules engine, but fortunately it is also an out-of-the-box validator of Microsoft’s validation block.
Difficult? Not at all, when following these simple steps:
using System;
using Microsoft.Practices.EnterpriseLibrary.Validation;
using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;
public class Customer
{
[StringLengthValidator(0, 10)]
public string CustomerName;
public Customer(string name)
{
this.CustomerName = name;
}
}
class Program
{
static void Main(string[] args)
{
Customer customer = new Customer("Thunderbird");
Validator<Customer> validator = ValidationFactory.CreateValidator<Customer>();
ValidationResults results = validator.Validate(customer);
if (!results.IsValid)
{
foreach (ValidationResult result in results)
{
Console.WriteLine(result.Message);
}
}
}
}
Jun 5th
Recently, I followed a discussion about quality of software in zombie mode. Please do understand that not the software – but I – was in zombie mode.
The question under discussion was: who is to blame for poor software quality?
Is it the business, with their vague requirements? Or maybe the (project)managers, who only care for budget and scope? In any case the coders are to blame, are they?
Maybe all of the aforementioned?
Personally, I am a (sort of) believer in Goldratt his theory of constraints, so the answer would be obvious. Loss of quality adds well to the pile of crap.
However, what first struck me was the omission of software architects (and testers). The omission suggests that there is no role for software architects in quality? Strange.
Therefore I would say: no wonder it is of poor quality, there is no software architect involved as a technical conscience. On the other hand, technique plays – of course – only a small part in the whole software development process. For creating quality software, all perspectives must thus be taken into account.
True. But what is the definition of quality code?
From a technical viewpoint you can have high-quality software, whilst from a business perspective the software doesn’t solve the problem that the business is looking for. The other way around can also be true.
Therefore, the motto of today:
Although the software is crappy, the business still can be happy!
That’s the power of a good UI/UX. Apple does understand this very well.
Jun 5th
In this mini-series of one post, I’ll show you how to generate SQL-script from an UML model.
First, you need a model. This can be any model, but here I use an UML model. The class diagram on the left shows a simple model consisting of a parent class and a related child class. Both are stereotyped <<table>> so you can see we are talking about a data model.
Both have some attributes. Note that their types have been declared explicitly.
The interesting part is their association. As you can see it is a traditional master-detail relationship. For clarity I have named the association and both association ends, but the latter is not strictly necessary.
This UML diagram can be represented in the following XML form:
<?xml version="1.0" encoding="utf-8"?>
<EntityModel>
<Entity Name="TestParent">
<Property Name="TestParentName1" Type="String" />
<Property Name="TestParentNumber" Type="Integer" />
</Entity>
<Entity Name="TestChild">
<Property Name="TestChildName" Type="String" />
</Entity>
<Association Name="FK_TestParent_TestChild">
<End Name="TestParent_End" Role="TestParent" Multiplicity="0..1" />
<End Name="TestChild_End" Role="TestChild" Multiplicity="*" />
</Association>
</EntityModel>
Why that is interesting? That is because XML easily can be transformed into something useful.
For performing the actual transformation you can use, for example:
Thus, it is transformed into a sql-script.
/****** Table [dbo].[TestParent] ******/ CREATE TABLE [dbo].[TestParent]( [TestParentID] [int] IDENTITY(1,1) NOT NULL, [TestParentName1] [varchar](MAX) NULL, [TestParentNumber] [int] NULL, CONSTRAINT [PK_ParentTable] PRIMARY KEY CLUSTERED ([TestParentID] ASC) ) GO /****** Table [dbo].[TestChild] ******/ CREATE TABLE [dbo].[TestChild]( [TestChildID] [int] IDENTITY(1,1) NOT NULL, [TestParentID] [int] NULL, [TestChildName] [varchar](50) NULL, CONSTRAINT [PK_ChildTable] PRIMARY KEY CLUSTERED ([TestChildID] ASC) ) GO /****** ForeignKey [FK_TestParent_TestChild] ******/ ALTER TABLE [dbo].[TestChild] ADD CONSTRAINT [FK_TestParent_TestChild] FOREIGN KEY([TestParentID]) REFERENCES [dbo].[TestParent] ([TestParentID]) GO
The keen eye will notice that in the final sql-script primary and foreign key columns are introduced, which are not present in the original model (diagram nor xml file). The other way around, specification of associations in the original model is much richer than the resulting foreign key constraint in the sql-script. These “mismatches” must be handled and are typically present when performing O/RM mapping.
May 21st
You must know that I am not an average person. No, not at all.
Like all great persons on earth and above: I have a true vision.
Unfortunately, it appears that it is merely a tunnel vision.
If you can choose between doing it the hard way or easy way. Which would you choose? I guess the easy way.
Not for me, I choose different. Because I am different.
Before I show you how my interesting brain works : first the easy way.
EXEC sp_rename '[TableName].[PK__TableName]', 'pkTableName', 'INDEX'
Well. Isn’t that easy? Indeed it is. Leave it at that.
However, as you probably could expect by now, I somehow managed to create something like this.
-- (1) drop foreign key constraint ALTER TABLE [dbo].[TableName] DROP CONSTRAINT [ForeignTableName_fk] -- (2) drop primary key constraint ALTER TABLE [dbo].[PrimaryTableName] DROP CONSTRAINT [PK__TableName__E258530B5AD97420] -- (3) recreate renamed primary key(s) ALTER TABLE [dbo].[PrimaryTableName] ADD CONSTRAINT [pkPrimaryKey] PRIMARY KEY CLUSTERED ( [PrimaryKeyID] ) ON [PRIMARY] -- (4) recreate (renamed) foreign key(s) ALTER TABLE [dbo].[ForeignTableName] ADD CONSTRAINT [ForeignTableName_fk] FOREIGN KEY ( [ForeignKeyID] ) REFERENCES [dbo].[PrimaryTableName] ( [PrimaryKeyID] ) ON UPDATE CASCADE ON DELETE CASCADE
I’ll be honest with you, the real thing was much worse. But how could this happen?
It started with trying to rename primary key constraints. Brainstorming, I came up with something like ‘ALTER TABLE … MODIFY CONSTRAINT’. Hmm, such a statement doesn’t exist. No problem, that minor issue easily can be resolved by dropping the constraint and recreate it, but then with a different name.
But wait. That doesn’t work, those pesky foreign key constraints prevent this mighty task of renaming the primary key. Hard thinking, brain overload. Brain suggests to drop and recreate all foreign keys then. Some munk work is to expected, but after a couple of hours hard work it probably will work.
At that moment a brainwave emerged in a corner of my empty skull:
“Wouldn’t it be nice if you could use something like sp_rename, as normally used for renaming tables and columns?”
Eh-oh, resurrection of Teletubbie brain. That is possible!
May 6th
Sometimes, you want to do some simple validation. For example, data should not exceed the reserved storage size for the field in the database.
In this example CustomerName must be less than 10 characters. So, the client code should look like this:
Customer customer = new Customer();
// customer name must be less than 10 characters
customer.CustomerName = this.textBox1.Text;
// Validation facade
ValidationResults results = Validation.Validate<Customer>(customer);
// populate listbox with validation results
foreach (ValidationResult result in results)
{
this.listBox1.Items.Add(result.Message);
}
The customer name is filled with input from a textbox. The complete customer object is validated using a validation facade. Finally, a list box is populated with the validation results.
Use of a facade simplifies use of validation in the client. The facade itself looks like this:
public static class Validation
{
public static ValidationResults Validate<T>(T validationobject)
{
Validator<T> validator = ValidationFactory.CreateValidator<T>();
ValidationResults results = validator.Validate(validationobject);
return results;
}
}
But wait! This looks exactly like the Validation Application Block. That’s a coincidence!
Indeed. Since the callings are similar you easily can replace the plumbing with the real stuff later on if you want.
But be aware that there is a small difference. This simplified version does not use attributes, but self validation by implementing an ISelfValidation interface.
public interface ISelfValidation
{
void Validate(ValidationResults results);
}
The object in question implements ISelfValidation as follows:
class Customer : ISelfValidation
{
public string CustomerName { get; set; }
public void Validate(ValidationResults results)
{
int maxLength = 10;
string validationString = CustomerName;
ValidateStringLength(results, validationString, maxLength);
}
// this can be put into a helper class if you want
private static void ValidateStringLength(ValidationResults results, string validationstring, int maxlength)
{
if (validationstring.Length > maxlength)
{
results.Add(new ValidationResult(String.Format("Length must be less than {0}", maxlength)));
}
}
}
This way simple validation becomes very easy. So, kids please do try this at home.
Download(s) : [Download not found]
Apr 30th
Do you know FxCop?
FxCop is an application that analyzes managed code assemblies. Many of the issues concern violations of the programming and design rules set forth in Design Guidelines.
Today, I announce my wish for an equivalent for SQL Database Analysis.
As it happens over time a database structure grows, and grows. Sometimes, it grows like wild grass. At other times, the database is restructured by someone who smoked to much wild grass.
There are two problems here:
For .NET code you can use FxCop or StyleCop, but serious tooling is lacking for databases.
Therefore – all you tool belt lovers – lets unite and demand for a tool called SqlCop.