Wednesday, May 30, 2007

To schema or not to schema...

Today we ran into a very practical problem. Should schema names be included in the NHibernate mapping ? Well it depends a little bit on your back end. In Oracle the username is the schema name. In SQL server you have the Database concept. (Northwind database for example.) For one customer we generated a NHibernate business object layer with table mapping like so:
class name = "Customers" table= "Abel.Customers"
However when moving to production, the Oracle User / Schema name was different. So our code did not work. All we needed to do is take of the Able schema part to make it work with the production connection string.
We have immediately decided to make this a GenWise Option for the Table item template. So now you can generate the mapping with or without schemanames

Saturday, May 12, 2007

NHibernate Configuration from Code

Sometimes you do not want the connectstring in your NHibernate.config file. In fact setting it there without encryption seems not the right thing to do. Before you open sessions in NHibernate you can configure NHibernate to take connection settings from code. This way you can for instance let the user log in with his/her database username and or password:

_configuration = new NHibernate.Cfg.Configuration();
_configuration.SetProperty("hibernate.connection.provider",@"NHibernate.Connection.DriverConnectionProvider");
_configuration.SetProperty("hibernate.dialect",@"NHibernate.Dialect.Oracle9Dialect");
_configuration.SetProperty("hibernate.connection.driver_class",@"NHibernate.Driver.OracleDataClientDriver");
_configuration.SetProperty("hibernate.connection.connection_string",@"persist security info=True;data source=MyServer; user id=MyUserid; password=MyPassword;");

This example uses Oracle settings.
On the Web you will probably get the username and password somewhere from a session variable.

string _username = HttpContext.Current.Session["Username"].ToString();
string _password = HttpContext.Current.Session["Password"].ToString();
_Configuration.SetProperty("hibernate.connection.connection_string", @"persist security info=True;data source=RADORA9; user id=" + _username + "; password=" + _password + ";");

Friday, May 11, 2007

What is Code Generation

The answer seems obvious. Code Generation is Code Generating Code. Basically it is a skeleton filled in by a parser looking for variable parts. Off course in it's simplest form that's what it is.

But there is much more to it. Straight code generation does not allow you to have an extensible framework to build upon. True code generation should build on a flexible object oriented code generation framework with a hierarchical template set in which you can hook either with custom code or with other templates. Thats' just what we have been building, and it is extremely powerful. Templates can independently from each other generate code not only into each other but in different files.

Our templates are C# classes that implement certain interfaces. Each template uses a codeblock structure. All templates expose code insertion points. For instance the following code:

PageTemplate.AtPageLoadEnd.Add("{0}_ActionChanged(\"Browse\");", PrimaryControl.Name);


used in a template generates at an ASX page code behind in the AtPageLoad event, in the last code block of the Aspx Page template. These code insertion points can be used in all templates.

Sunday, May 6, 2007

Some new template developments for GenWise.


We are working hard on our GenWise tool. See http://www.GenWise.com
Lately we have been adding some templates outside of the GenWise environment, just to see how that would work. GenWise templates are compiled .Net assemblies that can be plugged into the GenWise Code generation environment. The templates just have to implement some standard interfaces to work in the GenWise IDE. Here is a small example of a Code template that lets the programmer select a color code in the source code editor via a nice interface:

using System;
using GenWise.Framework.Generic;
using GenWise.Framework.Prj;
using GenWise.Framework.Templates;

namespace ColorCodeTemplate
{
/// Adds Color Code Template
[Serializable]
[Template("ColorCodeTemplate", "ColorCodeTemplate", "ColorCodeTemplate",
SymbolObjectType = typeof(ColorCodeTemplateSymbols),
SingleInstance = false
)
]
// The template For the ColorcodeSelection.
// Inherists from CodeTemplate that contains all basic functionality to make the template work.
public class ColorCodeTemplate : CodeTemplate
{
#region --- Constructors ---
/// Create a ColorCode Template specifying it's inital Parent Template
///
public ColorCodeTemplate(BaseTemplate pParentTemplate)
: base(pParentTemplate)
{
}
/// Create a Color Code Template specifying it's inital codeblock
public ColorCodeTemplate(BaseTemplate pParentTemplate, CodeBlock pCodeBlock)
: base(pParentTemplate, pCodeBlock)
{
}

#endregion

/// Creates the Symbol Object, these are the template prompts. These prompts can be maintained in a
/// XML file. An automatic interface can be used, or you can specific your own interface.
protected override ISymbolObject CreateSymbolObject()
{
return new ColorCodeTemplateSymbols(Symbols, this);
}

/// Overide the default designer. I have my own
public override System.Windows.Forms.UserControl GetDesigner()
{
ColorPicker CPick = new ColorPicker(this, Options.SelectedColor.GetValueOrDefault());
CPick.ShowDialog();
return null;
}
/// Template Options
public ColorCodeTemplateSymbols Options
{
get { return (SymbolsObject as ColorCodeTemplateSymbols); }
}
/// Validates that the Symbols are correctly configured. No required, but if there are own validations add them here.
public override ValidationResult Validate(bool pRecursive, bool pFullValidation)
{
ValidationResult _result = base.Validate(pRecursive, pFullValidation);

if (!_result.IsValid) return _result; // Do not continue checking stuff if the base already fails.

if (Item.NeedsRegeneration == GenerationUpdateStatus.NotNeeded)
{
if (AttachedCodeBlock.File.FileExtension != "cs")
_result.AddError(this, "This Template writes c# code thus it needs to be used inside a C# CodeBlock");
}

if (Options.SelectedColor == null)
_result.AddError(this, "There is no Color selected.");

return _result;
}

/// What needs to be generated comes here.
protected override void Generate()
{
if (!IsValid) return;

// When item is invalid, no code generation
if (!Item.IsValid) return;
and add the namespace
// The class builder in this case is the parent where we are adding this code template
//
if (ParentTemplate is IClassTemplate)
{
IClassTemplate _classTemplate = ParentTemplate as IClassTemplate;
_classTemplate.ClassBuilder.NameSpaces.Add(new NameSpace("System.Drawing", "System.Drawing"));
}

base.Generate();

// Write the Template code
CodeBlock.OpenRegion(ToString()); // Open a c# region in the source editor
string _fieldName = "_" + Name + "Color"; // the generated field name

CodeBlock.Add("Color {0} = Color.FromArgb({1},{2},{3});", _fieldName, Options.SelectedColor.Value.R.ToString(), Options.SelectedColor.Value.G.ToString(), Options.SelectedColor.Value.B.ToString());

CodeBlock.AddUser("AfterColorAssigned", "After the color is assigned");
CodeBlock.CloseRegion(); // close the openend editor region.

}

}
}