使用过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. nginx+tomcat负载均衡+动静分离+redis集中管理session

    1.服务器A安装ng,服务器B.C安装tomcat: 2.服务器A建立/data/www目录,用于发布静态文件: 3.ng无动静分离配置: user root root; worker_process ...

  2. php的header()函数之设置content-type

    //定义编码 header( 'Content-Type:text/html;charset=utf-8 '); //Atom header('Content-type: application/at ...

  3. easyui常现错误

    1.easyui-tabs:当data-options的属性设置为true时,其tab内部的内容显示不出来. 2.设置easyui-panel的title格式及字体大小无效 解决方法:在设置title ...

  4. java中基础类型的初始值,以及一些平时不注意的小知识

    有时候总是卡在一些类型的初始值上,今天闲下来就来自己给自己记录一下. String   a; 如果直接打印会提示未初始化.并且未初始化的a不能比较. 这时,我们定义个person类 person{ S ...

  5. Number Sequence 分类: HDU 2015-06-19 20:54 10人阅读 评论(0) 收藏

    Number Sequence Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Tot ...

  6. Poj(2253),Dijkstra松弛条件的变形

    题目链接:http://poj.org/problem?id=2253 题意: 给出两只青蛙的坐标A.B,和其他的n-2个坐标,任一两个坐标点间都是双向连通的.显然从A到B存在至少一条的通路,每一条通 ...

  7. 动态规划(DP),模拟

    题目链接:http://poj.org/problem?id=1088 Memory: 252KTime: 16MSLanguage: C++Result: Accepted 解题报告: 1.lm[i ...

  8. servlet中Java连接数据库后的基本操作

    servlet中Java连接数据库后的基本操作 在eclipse中新建一个工程:login 在Server中新建一个服务器,基本的操作不用说了,在前两天的笔记中可以找到; 需要知道数据库的用户名和密码 ...

  9. NOIP 营业额统计 splay tree 纯模板

    2924: 营业额统计 Time Limit(Common/Java):1000MS/3000MS     Memory Limit:65536KByteTotal Submit: 389       ...

  10. zoj 3557 How Many Sets II

    How Many Sets II Time Limit: 2 Seconds      Memory Limit: 65536 KB Given a set S = {1, 2, ..., n}, n ...