使用 XAF 完成工作 - 第 1 部分






4.14/5 (7投票s)
eXpressApp Framework (XAF) 教程
引言
如果开发一个相当复杂的应用程序变得非常容易,就像创建几个类然后就可以收工一样,会怎么样?这需要付出代价,但我们都知道天下没有免费的午餐。
好消息是,该解决方案仅包含 63 行代码。事实上,这正是我真正想告诉你的,用最少的工作量完成任务。
我们只需要创建一些域对象类,无需编写 Windows Forms 或 ASP.NET 代码,仍然可以获得功能齐全的 Windows Forms 和 ASP.NET 应用程序。

XAF 来自 DevExpress,是一个框架,使我们能够以最少的开发工作量创建各种应用程序。开箱即用,它提供了许多在开发业务线 (LOB) 应用程序时通常需要的功能。XAF 利用了 DevExpress 的 .NET 组件和 XPO - 他们的对象关系映射 (ORM) 解决方案。

要求
您可以通过 DXperience Universal Subscription 获得 XAF。该产品也有免费试用版。
创建解决方案
使用 Visual Studio 的“新建项目”对话框,以通常的方式创建一个新的基于 XAF 的解决方案。

通过选择“应用程序解决方案”,我们可以得到一个包含 Windows Forms 和 Web 应用程序的解决方案。我认为这很棒,初始解决方案看起来是这样的:

此时,我们需要为 Windows Forms 项目 `XAFSmartBooking.Win` 打开 `app.config` 文件,为 Web 应用程序项目 `XAFSmartBooking.Web` 打开 `Web.Config` 文件。取消注释我们想要的连接字符串,然后保存并构建解决方案。
现在我们有了一个 Windows Forms 应用程序

以及一个 Web 应用程序

很高兴从一开始就内置了用户管理功能,而且无需编写任何代码。
创建域对象
由于我们正在处理一个预订应用程序,我们需要预订某些东西,如果你愿意,可以称之为可预订对象。右键单击 `XAFSmartBooking.Module` 项目,然后选择“添加”->“新项”。

我们创建一个名为 `Bookable` 的新域对象,这将是我们可预订对象的 `abstract` 基类。起初,我想能够预订建筑物、房间和车辆。所以我们只是使用相同的过程添加所需的类型,从而形成一个简单的层次结构。

代码
`Bookable` 是我们的基域对象实体,它继承自 `BaseObject`,这是所有 XAF 域对象都继承的预定义类。我们定义了一个 `string` 属性“`Name`”,并为其添加了 `[Size(255)]` 属性定义。`Size` 属性用于声明底层数据存储中字段的大小。
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("Name", ref name, value);
}
}
}
`Facility` 是 `Building` 和 `Room` 的共同基类。它还公开了一个 `PhoneNumber` 类型的属性,这是 XAF 业务类库中的众多预定义类之一。
在构造时,如果我们的域对象不在加载状态,我们就会创建一个 `PhoneNumber` 类的新实例。如果实体已存在于数据存储中,并且构造函数在加载操作期间被调用,那么该域对象就处于加载状态。
为了方便在保存 `Facility` 对象时保存 `phonenumber`,我们重写了 `OnSave` 方法,并保存了电话号码。
`[ExpandObjectMembers(ExpandObjectMembers.InDetailView)]` 属性声明强制展开 `PhoneNumber` 上定义的属性,用于 `Facility` 对象的详细视图。
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",
ref phoneNumber, value);
}
}
}
`TypeBase` 将用作用于区分各种类型的建筑物、房间和车辆的类的基类。
`[NonPersistent]` 属性确保 XAF,或者更准确地说 XPO,不会为该类型创建表。`Name` 属性将与直接子类的属性存储在同一个表中。`[Indexed(Unique=true)]` 指示 XAF 在用于存储属性的列上创建唯一索引。该列对于子类是唯一的,而不是对于 `TypeBase` 类的实例。
[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("Name", ref name, value);
}
}
}
`BuildingType` 是用于定义 `Bookable` 子类判别符的三类之一,另外两类是 `RoomType` 和 `VehicleType`。
`[Association("Building-BuildingType", typeof(Building))]` 定义了 `BuildingType` 和 `Building` 之间的一对多关系的“一”侧。`Buildings` 属性返回关联的 `Building` 对象作为集合。
[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 Buildings
{
get
{
return GetCollection("Buildings");
}
}
}
这是我们的 `Building` 类。它包括与 `BuildingType` 类的一对多关联的“多”侧,并且还使用了 XAF 业务类库中的另一个预定义类 `Address`。
[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);
}
}
}
结论
这再简单不过了。仅用 63 行代码,我们就创建了一个可以自行维护数据存储的解决方案。XAF 支持流行的数据库管理系统,如 Microsoft SQL Server、IBM DB2、Oracle RDBMS 等。
作为额外的奖励,我们同时拥有一个 Windows Forms 应用程序和一个 ASP.NET 应用程序。
本系列的下一部分将添加对预订的支持,而且看起来也会很棒。
历史
- 2011 年 1 月 12 日 - 首次发布
- 2011 年 1 月 14 日 - 在页面顶部添加了 XAF 链接