XAF应用开发教程(二)业务对象模型之简单类型属性

使用过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.为客户类填加属性,填加属性后将对应着数据库中的字段:

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

  1 using System;
  2 using System.Linq;
  3 using System.Text;
  4 using DevExpress.Xpo;
  5 using DevExpress.ExpressApp;
  6 using System.ComponentModel;
  7 using DevExpress.ExpressApp.DC;
  8 using DevExpress.Data.Filtering;
  9 using DevExpress.Persistent.Base;
 10 using System.Collections.Generic;
 11 using System.Drawing;
 12 using DevExpress.ExpressApp.Model;
 13 using DevExpress.Persistent.BaseImpl;
 14 using DevExpress.Persistent.Validation;
 15 
 16 namespace XCRMDemo.Module.BusinessObjects
 17 {
 18     [DefaultClassOptions]
 19     //[ImageName("BO_Contact")]
 20     //[DefaultProperty("DisplayMemberNameForLookupEditorsOfThisType")]
 21     //[DefaultListViewOptions(MasterDetailMode.ListViewOnly, false, NewItemRowPosition.None)]
 22     //[Persistent("DatabaseTableName")]
 23     // Specify more UI options using a declarative approach (https://documentation.devexpress.com/eXpressAppFramework/CustomDocument112701.aspx).
 24     public class 客户 : BaseObject
 25     {
 26         // Inherit from a different class to provide a custom primary key, concurrency and deletion behavior, etc. (https://documentation.devexpress.com/eXpressAppFramework/CustomDocument113146.aspx).
 27         public 客户(Session session)
 28             : base(session)
 29         {
 30         }
 31 
 32         public override void AfterConstruction()
 33         {
 34             base.AfterConstruction();
 35             // Place your initialization code here (https://documentation.devexpress.com/eXpressAppFramework/CustomDocument112834.aspx).
 36         }
 37 
 38         //姓名、禁用、性别、出生日期、手机号码、地址、年收入、照片
 39         private string _姓名;
 40 
 41         public string 姓名
 42         {
 43             get { return _姓名; }
 44             set { SetPropertyValue("姓名", ref _姓名, value); }
 45         }
 46 
 47         private bool _禁用;
 48 
 49         public bool 禁用
 50         {
 51             get { return _禁用; }
 52             set { SetPropertyValue("禁用", ref _禁用, value); }
 53         }
 54 
 55         private 性别 _性别;
 56 
 57         public 性别 性别
 58         {
 59             get { return _性别; }
 60             set { SetPropertyValue("性别", ref _性别, value); }
 61         }
 62 
 63         private DateTime _出生日期;
 64 
 65         public DateTime 出生日期
 66         {
 67             get { return _出生日期; }
 68             set { SetPropertyValue("出生日期", ref _出生日期, value); }
 69         }
 70 
 71         private string _手机号码;
 72 
 73         public string 手机号码
 74         {
 75             get { return _手机号码; }
 76             set { SetPropertyValue("手机号码", ref _手机号码, value); }
 77         }
 78 
 79         private string _地址;
 80 
 81         public string 地址
 82         {
 83             get { return _地址; }
 84             set { SetPropertyValue("地址", ref _地址, value); }
 85         }
 86 
 87         private decimal _年收入;
 88 
 89         public decimal 年收入
 90         {
 91             get { return _年收入; }
 92             set { SetPropertyValue("年收入", ref _年收入, value); }
 93         }
 94 
 95 
 96         [Size(SizeAttribute.Unlimited), VisibleInListView(true)]
 97         [ImageEditor(ListViewImageEditorMode = ImageEditorMode.PictureEdit,
 98             DetailViewImageEditorMode = ImageEditorMode.PictureEdit,
 99             ListViewImageEditorCustomHeight = 40)]
100         public byte[] 照片
101         {
102             get { return GetPropertyValue<byte[]>("照片"); }
103             set { SetPropertyValue<byte[]>("照片", value); }
104         }
105     }
106 
107     public enum 性别
108     {
109         男,女,未知
110     }
111 }

代码修改为上述内容后,我们再次运行系统,按下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 typeAdvantageAsaAseDB2FirebirdMySQLMS AccessMSSQLMSSQL CEOraclePervasive SQLPostgre SQLVistaDB
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 = 40)]
        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

posted @ 2015-12-22 10:20  code first life  阅读(5740)  评论(1编辑  收藏  举报