02 May

XAF Data Import Functionality

One of the biggest problems with migrating legacy applications to a new framework (such as XAF, netTiers, etc) is the process of importing existing data into the newly created application. I’ve always found this to be a challenging and boring step of the process, and usually it requires a fair bit of manual work or writing custom import functions or applications.

I think there are probably (generally) 3 common data import sources:

  • Flat File (CSV, TSV, etc)
  • XML File
  • Relational DBMS (Access, SQL, MySQL, etc)

As most of my projects these days are baed on XAF or XPO, I figured there must be a more generic way to do my data imports. XAF is an application framework built around eXtensible Persistent Objects (XPO) which is a proprietary ORM technology developed by (1)Developer Express.

XPO Objects are defined in classes which derive from XPObect (or other) base classes with various Attributes to further refine persistent behaviour.

I have added a few of my own custom Attributes to decorate my XPO classes and properties in order to hint my data import library with any additional data required for the import process. I have a custom application XpoImport which uses reflection to enumerate all the Xpo classes and properties within a specified namespace. This application creates two connections to the source and destination databases and provides a small amount of in-memory caching for lookup data. Some examples will follow.

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public class TableImportAttribute : Attribute
{
public readonly string SourceTable = string.Empty;
public readonly string KeyField = string.Empty;
// ...
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class FieldImportAttribute : Attribute
{
public readonly string SourceField = String.Empty;
public readonly FieldConversionType ConversionType = FieldConversionType.None;
public enum FieldConversionType
{
None,
IntegerToString,
StringToPhoneNumber,
Lookup,
Enum
}
// ...

The business objects must now be decorated with these properties as such: (this example demonstrates that the new “Area” XPO object data will be loaded from the “tblAreas” source SQL table using “AREAID” as the key. The Name property will be populated with data from the “SEARCHTEXT” field from the “tblAreas” source.)

[DefaultClassOptions]
[DefaultProperty("Description")]
[TableImport("tblAreas", "AREAID")]
[TableImportIndex(1)]
public class Area : XPObject
{
private string _Name;
[Size(20)]
[Indexed(Unique = true)]
[FieldImport("SEARCHTEXT")]
public string Name
{
get
{
return _Name;
}
set
{
SetPropertyValue("Name", ref _Name, value);
}
}
// ...

Once the required fields have been created, I run a small WinForms application which loads the business object assembly and iterates through the various objects to load the data.