使用过ORM的朋友对这一部分理解起来会非常快,如果没有请自行补习吧:D.

不说废话,首先,我们来开发一个简单的CRM系统,CRM系统第一个信息当然是客户信息。我们只做个简单 的客户信息来了解一下XAF好了。

新建项之后,可以看到如下代码界面:

using System;
using System.Linq;
using System.Text;
using DevExpress.Xpo;
using DevExpress.ExpressApp;
using System.ComponentModel;
using DevExpress.ExpressApp.DC;
using DevExpress.Data.Filtering;
using DevExpress.Persistent.Base;
using System.Collections.Generic;
using DevExpress.ExpressApp.Model;
using DevExpress.Persistent.BaseImpl;
using DevExpress.Persistent.Validation; namespace XCRMDemo.Module.BusinessObjects
{
[DefaultClassOptions]
//[ImageName("BO_Contact")]
//[DefaultProperty("DisplayMemberNameForLookupEditorsOfThisType")]
//[DefaultListViewOptions(MasterDetailMode.ListViewOnly, false, NewItemRowPosition.None)]
//[Persistent("DatabaseTableName")]
// Specify more UI options using a declarative approach (https://documentation.devexpress.com/eXpressAppFramework/CustomDocument112701.aspx).
public class 客户 : BaseObject
{ // Inherit from a different class to provide a custom primary key, concurrency and deletion behavior, etc. (https://documentation.devexpress.com/eXpressAppFramework/CustomDocument113146.aspx).
public 客户(Session session)
: base(session)
{
}
public override void AfterConstruction()
{
base.AfterConstruction();
// Place your initialization code here (https://documentation.devexpress.com/eXpressAppFramework/CustomDocument112834.aspx).
}
//private string _PersistentProperty;
//[XafDisplayName("My display name"), ToolTip("My hint message")]
//[ModelDefault("EditMask", "(000)-00"), Index(0), VisibleInListView(false)]
//[Persistent("DatabaseColumnName"), RuleRequiredField(DefaultContexts.Save)]
//public string PersistentProperty {
// get { return _PersistentProperty; }
// set { SetPropertyValue("PersistentProperty", ref _PersistentProperty, value); }
//} //[Action(Caption = "My UI Action", ConfirmationMessage = "Are you sure?", ImageName = "Attention", AutoCommit = true)]
//public void ActionMethod() {
// // Trigger a custom business logic for the current record in the UI (https://documentation.devexpress.com/eXpressAppFramework/CustomDocument112619.aspx).
// this.PersistentProperty = "Paid";
//}
}
}

1.为客户类填加属性,填加属性后将对应着数据库中的字段:

我将在代码中依次填加,姓名、禁用、性别、出生日期、手机号码、地址、年收入、照片,几个字段。

 using System;
using System.Linq;
using System.Text;
using DevExpress.Xpo;
using DevExpress.ExpressApp;
using System.ComponentModel;
using DevExpress.ExpressApp.DC;
using DevExpress.Data.Filtering;
using DevExpress.Persistent.Base;
using System.Collections.Generic;
using System.Drawing;
using DevExpress.ExpressApp.Model;
using DevExpress.Persistent.BaseImpl;
using DevExpress.Persistent.Validation; namespace XCRMDemo.Module.BusinessObjects
{
[DefaultClassOptions]
//[ImageName("BO_Contact")]
//[DefaultProperty("DisplayMemberNameForLookupEditorsOfThisType")]
//[DefaultListViewOptions(MasterDetailMode.ListViewOnly, false, NewItemRowPosition.None)]
//[Persistent("DatabaseTableName")]
// Specify more UI options using a declarative approach (https://documentation.devexpress.com/eXpressAppFramework/CustomDocument112701.aspx).
public class 客户 : BaseObject
{
// Inherit from a different class to provide a custom primary key, concurrency and deletion behavior, etc. (https://documentation.devexpress.com/eXpressAppFramework/CustomDocument113146.aspx).
public 客户(Session session)
: base(session)
{
} public override void AfterConstruction()
{
base.AfterConstruction();
// Place your initialization code here (https://documentation.devexpress.com/eXpressAppFramework/CustomDocument112834.aspx).
} //姓名、禁用、性别、出生日期、手机号码、地址、年收入、照片
private string _姓名; public string 姓名
{
get { return _姓名; }
set { SetPropertyValue("姓名", ref _姓名, value); }
} private bool _禁用; public bool 禁用
{
get { return _禁用; }
set { SetPropertyValue("禁用", ref _禁用, value); }
} private 性别 _性别; public 性别 性别
{
get { return _性别; }
set { SetPropertyValue("性别", ref _性别, value); }
} private DateTime _出生日期; public DateTime 出生日期
{
get { return _出生日期; }
set { SetPropertyValue("出生日期", ref _出生日期, value); }
} private string _手机号码; public string 手机号码
{
get { return _手机号码; }
set { SetPropertyValue("手机号码", ref _手机号码, value); }
} private string _地址; public string 地址
{
get { return _地址; }
set { SetPropertyValue("地址", ref _地址, value); }
} private decimal _年收入; public decimal 年收入
{
get { return _年收入; }
set { SetPropertyValue("年收入", ref _年收入, value); }
} [Size(SizeAttribute.Unlimited), VisibleInListView(true)]
[ImageEditor(ListViewImageEditorMode = ImageEditorMode.PictureEdit,
DetailViewImageEditorMode = ImageEditorMode.PictureEdit,
ListViewImageEditorCustomHeight = )]
public byte[] 照片
{
get { return GetPropertyValue<byte[]>("照片"); }
set { SetPropertyValue<byte[]>("照片", value); }
}
} public enum 性别
{
男,女,未知
}
}

代码修改为上述内容后,我们再次运行系统,按下F5.

可以看到,我们新建的业务对象“客户”已经在菜中显示了,按下New按钮后,可以看到详细界面。

上面就是新建客户信息的界面了。下面我们来分析一下原理:

在代码中,我们使用了ORM工具,XPO定义了一个客户类,XPO运行时,分根据代码中的属性创建出数据库字段,下图是数据库中的表情况:

可以看出,xpo自动为我们建立了“客户”表,字段与“客户”类中的属性是一一对应的,但Oid,OptimisticLockField,GCRecord三个字段是我们没有建立的属性,却出现了,其中:

Oid,是GUID类型,主键,这是因为我们的代码中是这样写的:

public class 客户 : BaseObject

Oid是在BaseObject中定义的,所以客户类会自动建立这个字段。

OptimisticLockField:是XAF为了解决并发冲突而建立的字段。

GCRecord:继承自BaseObject的类在删除记录时只是逻辑删除,即只是将GCRecord中记录一个值,而没有删除的记录则为Null.
属性的写法:

最简单的,当我们想在数据库中定义一个字段时,可以在xpo类中写一个属性,当然这种说法很肤浅,但是为了方便理解,刚开始时这样认为就可以了。
 39         private string _姓名;
40
41 public string 姓名
42 {
43 get { return _姓名; }
44 set { SetPropertyValue("姓名", ref _姓名, value); }
45 }
这个属性和以往开发中的方法没有什么大的不同,仅是在set部分调用了SetPropertyValue方法,xpo为我们提供了一系列基类,SetPropertyValue是多数类中都有的,它的功能是可以在有值被设置时,需要得到属性变化时可以及时的得到通知。
当然,也可以直接使用
public string 姓名{get;set;}
这样来定义出姓名属性,但是有些场景时却会带来麻烦。
如:
public int 数量{get;set;}
public int 价格{get;set;}
public int 总价{get{return 数量*价格;}}
在数量和价格发生变化时,我们却看不到总价发生变化,因为控件不知道数量、价格已经变化了。所以我们应该尽量使用SetPropertyValue进行写set. 可以看到,字符串类型的姓名,在界面上最终显示成了一个文本框,XAF中内置了很多这样的控件,与类型做出了对应关系,当我们使用对应的类型时,就会自动使用对应的控件,这里的控件被叫做编辑器(PropertyEditor)。 接下来,有禁用属性:
        private bool _禁用;

        public bool 禁用
{
get { return _禁用; }
set { SetPropertyValue("禁用", ref _禁用, value); }
}

同样的,在视图中可以看到一个CheckBox编辑器出现了。

  private DateTime _出生日期;

        public DateTime 出生日期
{
get { return _出生日期; }
set { SetPropertyValue("出生日期", ref _出生日期, value); }
}

DateTime类型,直接使用CLR类型Datetime,日期型字段将在数据库中创建。

可以看出,xpo使用clr类型映射到了数据中字段的类型,下表中说明了数据库表中的字段类型与CLR类型的对应关系:

字段映射

除了自动建立的3个字段外,别的字段都是与代码有对应关系的映射了,xpo默认支持以下几种类型的映射:

C# System data type Advantage Asa Ase DB2 Firebird MySQL MS Access MSSQL MSSQL CE Oracle Pervasive SQL Postgre SQL VistaDB
System.Boolean logical bit bit char(1) char(1) bit bit bit bit number(1,0) bit bool Bit
System.Byte short tinyint tinyint smallint numeric(3,0) tinyint unsigned byte tinyint tinyint number(3,0) smallint smallint Int
System.SByte short numeric(3,0) numeric(3,0) numeric(3,0) numeric(3,0) tinyint short numeric(3,0) numeric(3,0) number(3,0) numeric(3,0) smallint SmallInt
System.Char char(1) char(1) nchar(1) char(1) char CHARACTER SET UNICODE_FSS char char(1) nchar(1) nchar(1) nchar char(1) char(1) NChar
System.Decimal money money money decimal(28,4) decimal(18,4) double currency money numeric(19,4) number(19,5) decimal(20,4) decimal(28,8) Decimal
System.Double double double precision double precision double precision double precision double double double precision float double precision double double precision Float
System.Single double float float float float real single float real float real real Float
System.Int16 short smallint smallint smallint smallint smallint short smallint smallint number(5,0) smallint smallint SmallInt
System.UInt16 integer numeric(5,0) numeric(5,0) numeric(5,0) numeric(5,0) smallint unsigned int numeric(5,0) numeric(5,0) number(5,0) numeric(5,0) numeric(5,0) Int
System.Int32 integer int numeric(10,0) int integer int int int int int integer int Int
System.UInt32 money numeric(10,0) numeric(10,0) numeric(10,0) numeric(10,0) int unsigned decimal(10,0) numeric(10,0) numeric(10,0) numeric(10,0) numeric(10,0) numeric(10,0) BigInt
System.Int64 money bigint numeric(20,0) bigint bigint bigint decimal(20,0) bigint bigint number(20,0) bigint bigint BigInt
System.UInt64 money numeric(20,0) numeric(20,0) numeric(20,0) numeric(18,0) bigint unsigned decimal(20,0) numeric(20,0) numeric(20,0) number(20,0) numeric(20,0) numeric(20,0) BigInt
System.Guid char(36) UNIQUEIDENTIFIERSTR char(36) char(36) char(36) char(38) guid uniqueidentifier uniqueidentifier char(36) char(36) char(36) UniqueIdentifier
System.Enum underlying type underlying type underlying type underlying type underlying type underlying type underlying type underlying type underlying type underlying type underlying type underlying type underlying type
System.String char varchar nvarchar varchar char varying varchar varchar nvarchar nvarchar nvarchar2 varchar varchar NVarChar
System.DateTime timestamp datetime datetime timestamp timestamp datetime datetime datetime datetime date timestamp timestamp DateTime
System.TimeSpan double double precision double precision double precision double precision double double double precision float double precision double double precision Float
System.Byte[] blob image image blob blob LONGBLOB longbinary image, in SQL Server
versions prior to 2005;
otherwise - varbinary
image blob longvarbinary bytea VarBinary
Unlimited size string memo text text clob BLOB SUB_TYPE TEXT longtext LONGTEXT ntext, in SQL Server
versions prior to 2005;
otherwise - nvarchar
ntext nclob longvarchar text NText
 

上面所描述的是都简单类型,其中枚举类型、图像类型、颜色,相对特殊一些,例如枚举类型:

在代码中,我们可以看到如下属性定义
 55         private 性别 _性别;
56
57 public 性别 性别
58 {
59 get { return _性别; }
60 set { SetPropertyValue("性别", ref _性别, value); }
61 }
这里的性别是一个枚举类型,定义如下:
107     public enum 性别
108 {
109 男,女,未知
110 }
打开详细视图,运行效果如下:


可以看出,XAF为我们使用类型进行了推导,自动使用了下拉框,并且取得到了枚举中有哪些值,显示在列表中供我们选择。XAF中的这种自动机制使用得非常多,后续我们将会看到。

图片的存储:
[Size(SizeAttribute.Unlimited), VisibleInListView(true)]
[ImageEditor(ListViewImageEditorMode = ImageEditorMode.PictureEdit,
DetailViewImageEditorMode = ImageEditorMode.PictureEdit,
ListViewImageEditorCustomHeight = )]
public byte[] 照片
{
get { return GetPropertyValue<byte[]>("照片"); }
set { SetPropertyValue<byte[]>("照片", value); }
}

图片的存储稍微有些不一样,在属性的get方法中,使用了GetPropertyValue<byte[]>来取值。

并且使用了几种Attribute,Attribute是为了扩展元数据的描述信息,简单来说,C#(.net)下面的语言不可能是无止境扩展的,所以提供了这样一种特殊的类,可以用来修饰程序中的无素,如assembly,class,interface,property,field,method等 等 .

xpo+xaf定义了很多的Attribute用来描述和扩展元数据信息,其中:

Size(SizeAttribute.Unlimited) 的意义是,创建数据库字段时,长度不限。SizeAttribute.Unlimited的值其实是-1,当然有些场景会用到限制长度。如

[Size(100)] //姓名字段数据库类型将是nvarchar(100)

public string 姓名{......}

[ImageEditor(ListViewImageEditorMode = ImageEditorMode.PictureEdit, DetailViewImageEditorMode = ImageEditorMode.PictureEdit,ListViewImageEditorCustomHeight = 40)]
这里设置了图像所使用的编辑器的参数,列表下面如何显示,详细视图下面如何显示,列表上显示时控制高度。 因为本节主要介绍业务对象的创建方法,不扩展讨论Attribute的用法,后续章节详细描述。 下节介绍几种常见的关系型数据库节构在ORM中的实现方法。
文章示例项目源码下载

QQ:4603528 QQ群:336090194

XAF应用开发教程(二)业务对象模型之简单类型属性的更多相关文章

  1. XAF应用开发教程(三)业务对象模型之引用类型与关联关系

    本节介绍信息系统开发中最常见的问题,引用关系,一对多关系,多对多关系. 以客户信息为例,客户通常需要客户分类,如VIP客户,普通客户,潜在客户.当然,我们可以定义枚举类型进行定义出这个类型,并在客户类 ...

  2. MIP开发教程(二) 使用MIP-CLI工具调试MIP网页

    初始化 MIP 配置 新建一个 MIP 网页 编写 MIP 网页代码 校验 MIP 网页 调试 MIP 网页 1. 初始化 MIP 配置 首先在html目录下进行初始化 MIP 配置: $ mip i ...

  3. 公众号第三方平台开发 教程二 component_verify_ticket和accessToken的获取

    公众号第三方平台开发 教程一 创建公众号第三方平台 公众号第三方平台开发 教程二 component_verify_ticket和accessToken的获取 公众号第三方平台开发 教程三 微信公众号 ...

  4. XAF应用开发教程-内置Attribute功能列表

    在 XAF 框架,一些用来生成一个业务应用程序的信息是在Attribute中指定.您可以将属性应用到业务类 (或它的成员) 指定验证规则,指定如何对数据进行显示. 设置关系类等.本主题提供了有关在何处 ...

  5. XAF应用开发教程(七)外观控制模块

    很多时候,我们需要按照不同的条件显示不同的效果,在传统的软件开发中,我们会直接使用 控件名称.BackColor,Enable,Visible等属性进行控制. 如果一个业务对象在多处使用,要么我们会去 ...

  6. XAF应用开发教程(六)控制器

    是的,XAF也是MVC结构的,但不仅限于MVC,ViewModel也存在,它是一项复合技术,AOP,ORM,MVC都有. 真实运行的系统中,仅有增删改查功能肯定是远远不够的,ERP.CRM等系统的开发 ...

  7. XAF应用开发教程(四)应用程序模型

    XAF是重量型框架,确实够重量的,方方面面都做得规规矩矩. 如果看了前面三节,可能会认为,这N多的Attribute到底都是从哪里来的?到底有多少这样的Attribute?如果不够用了怎么办?等着官方 ...

  8. XAF应用开发教程(一) 创建项目

    XAF是DevExpress公司的快速开发框架,全称eXpress Application Framework,是企业信息系统的开发利器,快速开发效果显著,在.net框架中,笔者至今没有找到一款可以与 ...

  9. XAF应用开发教程(八) 汉化与多国语言支持

    使用了XAF开发时,汉化是一个比较常的问题. 要实现汉化很简单: 1.在这里下载汉化资源文件.这里演示的版本是15.1.X的 2.文件下载后将:文件解压到目录    <你的项目>\BIN\ ...

随机推荐

  1. Virtualbox后台管理之VBoxManage

    Virtualbox是提供了后台启动的.只是不是默认的. 查看有哪些虚拟机 VBoxManage list vms 查看虚拟的详细信息 VBoxManage list vms --long 查看运行着 ...

  2. 这个Glance的界面该怎么看出问题,为什么状态是SOCKT?

    这个glance的状态图有问题吗?

  3. Oracle 11gR2新建空表不分配Segment

    一.引言: 在看<收获,不止Oracle>的神奇,走进逻辑体系世界一章时,需要新建一张表查看Extents的情况,由于该书的环境是ORACLE10G的,因此新建空表以后立刻就分配Segme ...

  4. POJ 2763:Housewife Wind(树链剖分)

    http://poj.org/problem?id=2763 题意:给出 n 个点, n-1 条带权边, 询问是询问 s 到 v 的权值, 修改是修改存储时候的第 i 条边的权值. 思路:树链剖分之修 ...

  5. 在Ecshop后台打印订单页面将商品按货号排序

    ECSHOP后台管理里的“打印订单" 页面里的商品排序有点乱,现在想改成按序号来排序,修改方法如下 下面是在2.7.2基础上做的修改 打开 admin/order.php  文件 找到(大约 ...

  6. greenplum集群安装

    一.环境配置 1.地址分配 192.168.1.201 mdw master 192.168.1.202 sdw1 segment1 192.168.1.203 sdw2 segment2 2.创建用 ...

  7. sharepint 数据视图 添加超链接

    1. 数值域清除数值,输入文本 详细进度 2. 添加连接 到 哪个页面 3. 将inteid拖过来 4. 连接到项目显示表单 5. 直接改下面的连接地址 <a href="http:/ ...

  8. python: linux下安装redis

    Python连接时报拒绝连接,需要重装redis: 1) 卸载redis sudo apt-get remove redis-server sudo apt-get autoremove 2)编译安装 ...

  9. ACM题目————星际之门(一)

    描述 公元3000年,子虚帝国统领着N个星系,原先它们是靠近光束飞船来进行旅行的,近来,X博士发明了星际之门,它利用虫洞技术,一条虫洞可以连通任意的两个星系,使人们不必再待待便可立刻到达目的地. 帝国 ...

  10. YTU 3004: 栈的基本运算(栈和队列)

    3004: 栈的基本运算(栈和队列) 时间限制: 1 Sec  内存限制: 128 MB 提交: 32  解决: 10 题目描述 编写一个程序,实现顺序栈的各种基本运算,主函数已给出,请补充每一种方法 ...