Introduction
What if it was really easy to develop a reasonable complex application, something along the lines of creating just a few classes and be done with it? This comes at a price, but then we all know that there is no such thing as a free lunch.
The good news is that the solution only contains 63 lines of code. Actually that's what I really want to tell you about, getting the job done with a minimal amount of work.
We are just going to create a number of Domain Object classes, no Windows Forms or ASP.NET coding, and still end up with functioning Windows Forms and ASP.NET applications.
XAF from DevExpress is a framework that allows us to create a wide range of applications with a minimum of development effort. Out of the box, it provides a lot of functionality commonly required during development of line of business (LOB) applications. XAF leverages DevExpress components for .NET, and XPO – their object relational mapping (ORM) solution.
Requirements
You get XAF with DXperience Universal Subscription. There is also a free trial of the product.
Creating the Solution
A new XAF based solution is created in the usual way, using the Visual Studio New Project Dialog.
By choosing the Applications Solution, we get a solution containing both a Windows Forms and a Web application. I think that’s a neat thing, and the initial solution looks like this:
At this point, we have to open the app.config for the Windows Forms project, XAFSmartBooking.Win and the Web.Config for the Web Application project XAFSmartBooking.Web
. Uncomment the connection strings we want, then save and build the solution.
We now have a Windows Forms Application:
and a Web Application:
It’s nice that user management is built in from the start, without a single line of code.
Creating Domain Objects
Since we are working on a booking application, we need something to book, a bookable object, if you want. Right click on the XAFSmartBooking.Module
project and select Add -> New Item.
We create a new Domain Object called Bookable
, this will be our abstract
base class for bookable objects. Initially, I’d like to be able to book buildings, rooms and vehicles. So we just add the required types using the same procedure giving us a simple hierarchy structure.
The Code
Bookable
is our base domain object entity, and it's derived from BaseObject
the predefined class that all XAF domain objects descends from. We define one string
property “Name
”, and give it a [Size(255)]
attribute definition. The Size
attribute is used to declare the size of the field in the underlying data storage.
public abstract class Bookable : BaseObject
{
private string name;
public Bookable(Session session)
: base(session)
{ }
public override void AfterConstruction()
{
base.AfterConstruction();
}
[Size(255)]
public string Name
{
get
{
return name;
}
set
{
SetPropertyValue<string>("Name", ref name, value);
}
}
}</string>
Facility
is the common base class for Building
and Room
. It also exposes a property of type PhoneNumber
, one of many predefined classes from the XAF Business Class Library.
During construction, we create a new instance of the PhoneNumber
class if our domain object is not in the loading state. A domain object is in a loading state if the entity already exists in the data storage, and the constructor is called during a load operation.
To facilitate saving of the phonenumber
, as part of a save operation for a Facility
object, we override the OnSave
method, and save the phone number.
The [ExpandObjectMembers(ExpandObjectMembers.InDetailView)]
attribute declaration forces expansion of the properties defined on the PhoneNumber
for detail views of Facility
objects.
public abstract class Facility : Bookable
{
private PhoneNumber phoneNumber;
public Facility(Session session)
: base(session)
{
if (!IsLoading)
{
phoneNumber = new PhoneNumber(session);
}
}
public override void AfterConstruction()
{
base.AfterConstruction();
}
protected override void OnSaving()
{
phoneNumber.Save();
base.OnSaving();
}
[ExpandObjectMembers(ExpandObjectMembers.InDetailView)]
public PhoneNumber PhoneNumber
{
get
{
return phoneNumber;
}
set
{
SetPropertyValue<phonenumber>("PhoneNumber",
ref phoneNumber, value);
}
}
}</phonenumber>
TypeBase
will be used as a base class for classes used to discriminate between various types of buildings, room, and vehicles.
The [NonPersistent]
attribute ensures that XAF, or rather XPO, does not create a table for this type. The Name
property will be stored in the same table as the properties of direct descendants. [Indexed(Unique=true)]
instructs XAF to create a unique index on the column used to store the property. The column will be unique for the descendant type, and not for instances of the TypeBase
class.
[NonPersistent]
public abstract class TypeBase : BaseObject
{
private string name;
public TypeBase(Session session)
: base(session)
{ }
public override void AfterConstruction()
{
base.AfterConstruction();
}
[Size(255)]
[Indexed(Unique=true)]
public string Name
{
get
{
return name;
}
set
{
SetPropertyValue<string>("Name", ref name, value);
}
}
}</string>
BuildingType
is one of the three classes used to define discriminators for our Bookable
descendants, the other two being RoomType
and VehicleType
.
[Association("Building-BuildingType", typeof(Building))]
defines the one side of a one-to-many relationship between BuildingType
and Building
. The Buildings
property returns the associated Building
objects as a collection.
[DefaultClassOptions]
[NavigationItem("Facilities")]
[ImageName("BO_Category")]
public class BuildingType : TypeBase
{
public BuildingType(Session session)
: base(session)
{}
public override void AfterConstruction()
{
base.AfterConstruction();
}
[Association("Building-BuildingType", typeof(Building))]
public XPCollection<building> Buildings
{
get
{
return GetCollection<building>("Buildings");
}
}
}</building></building>
Here is our Building
class. It includes the many side of the one-to-many association with the BuildingType
class, and it also uses another predefined class, Address
from the XAF Business Class Library.
[DefaultClassOptions]
[NavigationItem("Facilities")]
[ImageName("BO_Organization")]
public class Building : Facility
{
private BuildingType type;
private Address address;
public Building(Session session)
: base(session)
{
if (!IsLoading)
{
address = new Address(session);
}
}
public override void AfterConstruction()
{
base.AfterConstruction();
}
protected override void OnSaving()
{
address.Save();
base.OnSaving();
}
[Association("Building-BuildingType", typeof(BuildingType))]
public BuildingType Type
{
get
{
return type;
}
set
{
SetPropertyValue<buildingtype>("Type",
ref type, value);
}
}
[ExpandObjectMembers(ExpandObjectMembers.InDetailView)]
public Address Address
{
get
{
return address;
}
set
{
SetPropertyValue<address>("Address", ref address, value);
}
}
}
Concluding Remarks
It doesn’t get much easier than this. With just 63 lines of coding, we have created a solution that maintains its own data storage. XAF supports popular database management systems like Microsoft SQL Server, IBM DB2, Oracle RDBMS, and many more.
As an added bonus, we have both a Windows Forms application and an ASP.NET application.
The next part of the series will add support for booking, and it’s going to look nice too.
History
- 12th of January 2011 - Initial posting
- 14th of January 2011 - Added link to XAF at the top of the page