首页 > 学院 > 开发设计 > 正文

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

2019-11-14 13:40:17
字体:
来源:转载
供稿:网友

使用过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.Booleanlogicalbitbitchar(1)char(1)bitbitbitbitnumber(1,0)bitboolBit
System.Byteshorttinyinttinyintsmallintnumeric(3,0)tinyint unsignedbytetinyinttinyintnumber(3,0)smallintsmallintInt
System.SByteshortnumeric(3,0)numeric(3,0)numeric(3,0)numeric(3,0)tinyintshortnumeric(3,0)numeric(3,0)number(3,0)numeric(3,0)smallintSmallInt
System.Charchar(1)char(1)nchar(1)char(1)char CHARACTER SET UNICODE_FSScharchar(1)nchar(1)nchar(1)ncharchar(1)char(1)NChar
System.Decimalmoneymoneymoneydecimal(28,4)decimal(18,4)doublecurrencymoneynumeric(19,4)number(19,5)decimal(20,4)decimal(28,8)Decimal
System.Doubledoubledouble precisiondouble precisiondouble precisiondouble precisiondoubledoubledouble precisionfloatdouble precisiondoubledouble precisionFloat
System.SingledoublefloatfloatfloatfloatrealsinglefloatrealfloatrealrealFloat
System.Int16shortsmallintsmallintsmallintsmallintsmallintshortsmallintsmallintnumber(5,0)smallintsmallintSmallInt
System.UInt16integernumeric(5,0)numeric(5,0)numeric(5,0)numeric(5,0)smallint unsignedintnumeric(5,0)numeric(5,0)number(5,0)numeric(5,0)numeric(5,0)Int
System.Int32integerintnumeric(10,0)intintegerintintintintintintegerintInt
System.UInt32moneynumeric(10,0)numeric(10,0)numeric(10,0)numeric(10,0)int unsigneddecimal(10,0)numeric(10,0)numeric(10,0)numeric(10,0)numeric(10,0)numeric(10,0)BigInt
System.Int64moneybigintnumeric(20,0)bigintbigintbigintdecimal(20,0)bigintbigintnumber(20,0)bigintbigintBigInt
System.UInt64moneynumeric(20,0)numeric(20,0)numeric(20,0)numeric(18,0)bigint unsigneddecimal(20,0)numeric(20,0)numeric(20,0)number(20,0)numeric(20,0)numeric(20,0)BigInt
System.Guidchar(36)UNIQUEIDENTIFIERSTRchar(36)char(36)char(36)char(38)guiduniqueidentifieruniqueidentifierchar(36)char(36)char(36)UniqueIdentifier
System.Enumunderlying typeunderlying typeunderlying typeunderlying typeunderlying typeunderlying typeunderlying typeunderlying typeunderlying typeunderlying typeunderlying typeunderlying typeunderlying type
System.Stringcharvarcharnvarcharvarcharchar varyingvarcharvarcharnvarcharnvarcharnvarchar2varcharvarcharNVarChar
System.DateTimetimestampdatetimedatetimetimestamptimestampdatetimedatetimedatetimedatetimedatetimestamptimestampDateTime
System.TimeSpandoubledouble precisiondouble precisiondouble precisiondouble precisiondoubledoubledouble precisionfloatdouble precisiondoubledouble precisionFloat
System.Byte[]blobimageimageblobblobLONGBLOBlongbinaryimage, in SQL Server
versions prior to 2005;
otherwise - varbinary
imagebloblongvarbinarybyteaVarBinary
Unlimited size stringmemotexttextclobBLOB SUB_TYPE TEXTlongtextLONGTEXTntext, in SQL Server
versions prior to 2005;
otherwise - nvarchar
ntextncloblongvarchartextNText
 

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

在代码中,我们可以看到如下属性定义
 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群:50185791


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表