Blogs

Gary's Blog

XAF – Generating Business Classes for Existing Data Tables

     

The philosophy of XAF (the 80% case, if you will) is that the framework will be used for the creation of green field projects. Although that is how we expect the framework to be used in the majority of cases, this does not mean that we have forgotten about those developers who are working on applications for which there is already an existing database. In this post, we’ll look at how XAF supports the developer in generating business classes for existing data tables.

To generate these classes we are going to use the design time wizard; to do this, in the Solution Explorer, select the Add | New Item... context menu option within your common module, that’s the module that is used by both the Windows Forms and ASP.NET application projects:

Next, select the “Persistent Classes” template from the “Add New Item” dialog, and click on the “Add” button:

The Wizard will then open and you will be able to configure the connection string to your chosen database.

Multiple database systems (MS SQL Server, DB2, MySql, Firebird, etc) are supported by the wizard. Use the Provider combo box to select the required database type. Note that the corresponding database provider assembly must be available on your machine, otherwise the wizard will fail. :-)

Click “Next” and a dialog will open allowing you to select which table and columns are to be included. Note that tables with composite keys are not supported by XPO (the technology used under the hood to support XAF) and so such tables will not be included in the list:

Click the “Finish” button and the classes will be generated for you:

[Persistent("Customers")]
public class Customer : XPLiteObject {
    string fAddress;
    [Size(60)]
    public string Address {
        get { return fAddress; }
        set { SetPropertyValue<string>("Address", ref fAddress, value); }
    }
    //...
    string fCustomerID;
    [Key]
    [Size(5)]
    public string CustomerID {
        get { return fCustomerID; }
        set { SetPropertyValue<string>("CustomerID", ref fCustomerID, value); }
    }
    //...
    public Customer(Session session) : base(session) { }
    public Customer() : base(Session.DefaultSession) { }
    public override void AfterConstruction() { base.AfterConstruction(); }
}

Having done this, you’ll need to remember to remove the default constructor, as the default Session is not used to create objects in XAF.

With the classes generated, there is only one task left to complete. Currently, relationships between tables are not reflected in the auto generated classes. So, you'll have to declare the relationships manually:

[Persistent("Customers")]
public class Customer : XPLiteObject {
    [Association("Customer-Orders", typeof(Order)), Aggregated]
    public XPCollection Orders {
        get { return GetCollection("Orders"); }
    }
    string fCustomerID;
    [Key]
    [Size(5)]
    public string CustomerID { }
    //...
    public Customer(Session session) : base(session) { }
    public override void AfterConstruction() { base.AfterConstruction(); }
}
[Persistent("Orders")]
public class Order : XPLiteObject {
    Customer fCustomer;
    [Association("Customer-Orders")]
    public Customer Customer { }
    int fOrderID;
    [Key(true)]
    public int OrderID { }
    public Order(Session session) : base(session) { }
    //...
}

The code above demonstrates the One-to-Many relationship between Customer and Order objects. The "One" part of this relationship is represented by the Customer property of the Customer type in the Order class. The "Many" part is represented by the Orders property of the XPCollection type in the Customer class. Both these parts use the Association attribute.

To enable cascading deletion of the dependent objects (if a customer is deleted all the related orders for that customer are also deleted), you can specify the Aggregated attribute for the corresponding properties (see the Orders collection in the definition of the Customer class above).

Since the Customer field in the Order table now stores a link to the Customer object, you should populate it by the values that correspond to the values stored in the CustomerID field. For this purpose, you can write the following code in the module's updater:

public class Updater : ModuleUpdater {
    public override void UpdateDatabaseAfterUpdateSchema() {
        Order orderObject = Session.FindObject<Order>(CriteriaOperator.Parse("Customer is null"));
        while (orderObject != null) {
            if (!string.IsNullOrEmpty(orderObject.CustomerID)) {
                orderObject.Customer = Session.FindObject<Customer>(new BinaryOperator("CustomerID", orderObject.CustomerID));
                orderObject.Save();
            }
            orderObject = Session.FindObject<Order>(CriteriaOperator.Parse("Customer is null"));
        }
    }
}
As you an see from this post, even although XAF is aimed at the developer in a green field project, we have not forgotten those who are working on applications where the database tables already exist. By leveraging the wizard in XPO, XAF allows you to generate business classes for existing data tables.
Digg This
Published Mar 17 2009, 05:02 PM by Gary Short (DevExpress)
Filed under:
Technorati tags: XAF
Bookmark and Share

Comments

 

Alain Bismark said:

Hi Gary.

I think that is critical to generate the code of 1..n and m..n relationships too.

With this feature, we can create a prototype app from a legacy database more quickly.

Regards

March 17, 2009 5:27 PM
 

elpipo said:

+1 for Alain.  

It has already been requested in the past and other ORM's are have been doing this for years now, check out EntitySpaces for an excellent example ...  

March 17, 2009 6:13 PM
 

CESAR F. QüEB said:

Thank you for the tip. Anyway...

I'm agree with Alain's request.

TIA

March 17, 2009 6:14 PM
 

Gary Short (DevExpress) said:

Alain,

Yes we know the wizard is not perfect at the moment, but at least the whole process isn't manual ;-)

March 18, 2009 11:46 AM
 

shafat saeed said:

But how UpdateDatabaseAfterUpdateSchema works if the object is unknown. For example if there are many objects which participate into one to many relationship for example say 100 then how can we write code for UpdateDatabaseAfterUpdateSchema()

August 26, 2009 3:49 AM
 

goran sabados said:

Hi Gary,

I just tried this (we want to transfer all our applications programmed with MS Access, 14 years of work), but...

many (not all) Tables in Generating Persistent Classes for an Existing Database Wizard are empty! Do you have any idea why?

October 7, 2009 10:53 AM
 

Gary Short (DevExpress) said:

"Many tables are empty" Do you mean the generated classes? I mean the wizard wouldn't touch the tables in the database.

October 8, 2009 9:14 AM
 

goran sabados said:

right, not tables in database. Wizard window doesn't show any fields for many tables.

October 14, 2009 6:26 AM
 

goran sabados said:

"Many tables are empty" case :-)

on table with two columns, I changed Allow Nulls to True on Description (varchar), and after that table appeared in Wizard???

Maybe I have to do it on all fields in all tables?

October 20, 2009 7:05 AM
 

Jack Kenyon said:

I cant get this to work properly - does it work with MySQL.

It generates classes but they dont have all the attributes shown in the example.  eg...

there are no

[Persistent("xxxx")]

and no

[Size(nn)]

example of output follows------

using System;

using DevExpress.Xpo;

namespace hih_xaf_dev

{

 public class productimage : XPCustomObject

 {

   string fOid;

   [Key]

   [Size(38)]

   public string Oid

   {

     get { return fOid; }

     set { SetPropertyValue<string>("Oid", ref fOid, value); }

   }

   string fCaption;

   public string Caption

   {

     get { return fCaption; }

     set { SetPropertyValue<string>("Caption", ref fCaption, value); }

   }

   string fThumb;

   public string Thumb

   {

     get { return fThumb; }

     set { SetPropertyValue<string>("Thumb", ref fThumb, value); }

   }

   string fMedium;

   public string Medium

   {

     get { return fMedium; }

     set { SetPropertyValue<string>("Medium", ref fMedium, value); }

   }

   string fLarge;

   public string Large

   {

     get { return fLarge; }

     set { SetPropertyValue<string>("Large", ref fLarge, value); }

   }

March 1, 2010 2:25 AM
More from DevExpress
Live Chat
Have a pre-sales question?
Need assistance with your evaluation?
We are here to help.
Chat is one of the many ways you can contact members of the DevExpress Team. We are available Monday-Friday between 8:30am and 5:00pm Pacific Time.
If you need additional product information, require pre-sales assistance, or want help with your order, write to us at info@devexpress.com or call us at
+1 (818) 844-3383.