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.