XAF-Domain Components 技术 使用接口来定义ORM业务对象
一、简介
- 可以创建可重用的领域对象:多数情况下,每个XAF中用到的领域对象都不是唯一的,比较常见的对如:人、电话、地址,等领域对象,这些使用频率较高的,想要抽象出来还是有点难度的,这不是一个简单的任务,使用DC这事就简单了。
- 可以使用多重继承:因为DC是用接口描述的,所以,多继承在C#的语法级别被支持,你可以使用继承以前写过的DC,重用它,并且可以增加新的属性和替换逻辑。事实上,这是我最喜欢的一个特性!
- 不需要从持久性化基类继承实现领域对象 :最终的执行代码是生成的,这当然很容易实现了。当然,也可以指定基类。
- 在Medium Trust 环境中,DC组件不能使用。
- DC组件技术不支持Model First和Database first的方式。我们不推荐使用附加(就是两个或多个)数据库。因此,我们不提供任何手段从现有数据库生成域组件代码和逻辑,我们有没有立即的计划来支持此方案。请试试 XPO 或实体框架数据模型。
- 自定义字段不能在设计时添加到域组件。
- 如果一个DC组件注册为SharePart,不能添加自定义字段。
二、DC定义
[DomainComponent]
public interface IPerson {
string LastName { get; set; }
string FirstName { get; set; }
string FullName { get; }
void Copy(IPerson target);
}
你可以看到,接口上必须使用DomainComponentAttribute 来声明接口是个DC.接口的属性就是将来出来表的字段.在普通BO定义中使用的一些Attribute现在仍可用.例如你可以给LastName 上面加上 RuleRequiredFieldAttribute, 给接口上加上 NavigationItemAttribute. FullName 被定义为只读的.它需要在logic类中定义实现.另外Copy方法也必须在logic中实现.
三、注册DC
只有注册了DC后,才会被XAF生成真正的XPO类,下面是注册方法,需要打开Module.cs文件,实override下面的方法:
using DevExpress.Persistent.BaseImpl;
// ...
public override void Setup(XafApplication application) {
base.Setup(application);
XafTypesInfo.Instance.RegisterEntity("Person", typeof(IPerson));
}
上面的注册中,并没有指定基类,所以将会默认使用DCBaseObject 做为基类,如果要指定基类,可以看下RegisterEntity的其它重载方法。
四、Domain Logic
每个DC可以有一(零)个或多个Domain Logic. Domain Logic 是一个普通的类,加上了 DomainLogicAttribute 标记, 并指定DC类型. 其实再多的话都没有一个代码实例有用:
[DomainLogic(typeof(IPerson))] //必须写个,IPerson是指为哪个DC的逻辑
public class PersonLogic { //类别是任意的
public const string FullNameSeparator = " ";
public string Get_FullName(IPerson person) {
//Get_XXX Get_是固定的,实现property的get的方法,FullName是属性的名称
return string.Format("{0}{1}{2}", person.FirstName, FullNameSeparator, person.LastName);
}
public static void Copy(IPerson person, IPerson target) {
//实现了上面定义的Copy方法,但是,注意,第一个参数,在接口中并没有定义,但在这里却可以出现,也可以不出现,调用时会被自动替换为当前对象
if(target != null) {
target.FirstName = person.FirstName;
target.LastName = person.LastName;
}
}
}
上面的示例中,还可以看到,Get_FullName是非静态的,Copy是静态的,事实上,是不是静态的都没有关系,都会被调用,当然,你可以想像一下,静态方法是不需要实例化对象的。将来被调用时,是不会实例化PersonLogic这个类的。
否则就会实例化。当然,类中一个非静态方法都没有时,才会不实例化logic类。
那么,DC中的语法到底有多少呢?
| 说明 | 示例 |
|---|---|
|
Get_属性名称 当property的get被调用时,就执行这个方法。 |
public static string Get_FullName(IMyInterface instance)public static string Get_FullName(IMyInterface instance, IObjectSpace objectSpace) |
|
Set_属性名 当property的set被调用时,就执行这个方法。 |
public static void Set_FullName(IMyInterface instance, string value)public static void Set_FullName(IMyInterface instance, IObjectSpace objectSpace, string value) |
|
BeforeChange_属性名 当属性被设置新值之前被调用 |
public static void BeforeChange_FirstName(IMyInterface instance, string value)public static void BeforeChange_FirstName(IMyInterface instance, IObjectSpace objectSpace, string value) |
|
AfterChange_属性名 当属性被设置新值之后被调用. |
public static void AfterChange_FirstName(IMyInterface instance)public static void AfterChange_FirstName(IMyInterface instance, IObjectSpace objectSpace) |
|
方法名称 接口上定义了一个方法定义,那个方法被调用时,执行此处的逻辑。 |
public static void CalculateSalary(IMyInterface instance, int amount, int price)public static void CalculateSalary(IMyInterface instance, IObjectSpace objectSpace, int amount, int price) |
|
AfterConstruction Bo中有也有这个,就是新建对象完成后,可以在这里写一些初始化属性值的操作。 |
public static void AfterConstruction(IMyInterface instance)public static void AfterConstruction(IMyInterface instance, IObjectSpace objectSpace) |
|
OnDeleting Bo中也有这个,当删除时执行。 |
public static void OnDeleting(IMyInterface instance)public static void OnDeleting(IMyInterface instance, IObjectSpace objectSpace) |
|
OnDeleted Bo中有,删除后执行。 |
public static void OnDeleted(IMyInterface instance)public static void OnDeleted(IMyInterface instance, IObjectSpace objectSpace) |
|
OnSaving Bo中有也有这个,保存中执行。 |
public static void OnSaving(IMyInterface instance)public static void OnSaving(IMyInterface instance, IObjectSpace objectSpace) |
|
OnSaved Bo中有也有这个,保存完成执行。 |
public static void OnSaved(IMyInterface instance)public static void OnSaved(IMyInterface instance, IObjectSpace objectSpace) |
|
OnLoaded Bo中有也有这个,已经的对象,被加载后执行。 |
public static void OnLoaded(IMyInterface instance)public static void OnLoaded(IMyInterface instance, IObjectSpace objectSpace) |
上面的方法,必须是静态或是非静态的,必须为public,参数的定义可以是以下几种情况:
LogicMethodName(source_parameters)
与DC中定义的方法是一致的。LogicMethodName(target_interface, source_parameters)
当前DC类型,指当前对象和接口中定义的那些参数.LogicMethodName(target_interface, object_space, source_parameters)
与上面的相对,多了一个object_space,用过xpo+xaf的同学一看就懂了,就是指当前对象用的objectspace,因为有时我们需要使用objectspace进行一些crud操作.
五、示例:
之前的Logic你看起来可能感觉有点麻烦,下面来看看一种简写方法:
[DomainComponent]
public interface IPerson {
string FirstName { get; set; }
[NonPersistentDc]
string FullName { get; set; }
}
[DomainLogic(typeof(IPerson))]
public class PersonLogic {
IPerson person;
public PersonLogic(IPerson person) {
this.person = person; //构造逻辑时就传入了当前对象
}
//像BO中一样直接写property
public string FullName {
get { return person.FirstName; }
set { person.FirstName = value; }
}
}
下面是静态的实现方法:
[DomainComponent]
public interface IContact {
static string Name { get; }
}
[DomainLogic(typeof(IContact))]
public class ContactLogic {
public static string Name {
get { return "a constant string"; }
}
}
下面是如何使用ObjectSpace的示例:
[DomainLogic(typeof(IPerson))]
public class AdditionalPersonLogic {
public static void AfterConstruction(IPerson person, IObjectSpace objectSpace) {
person.Address = objectSpace.CreateObject<IAddress>();
}
}
下面来看看重写别的DC中定义的逻辑
[DomainComponent]
public interface IPerson {
[ImmediatePostData]
string FirstName { get; set; }
[ImmediatePostData]
string LastName { get; set; }
string DisplayName { get; }
}
[DomainLogic(typeof(IPerson))]
public class IPerson_Logic {
public string Get_DisplayName(IPerson person) {
return person.FirstName + " " + person.LastName;
}
}
[DomainComponent]
public interface IClient : IPerson {
[ImmediatePostData]
string ClientID { get; set; }
}
[DomainLogic(typeof(IClient))]
public class IClient_Logic {
public string Get_DisplayName(IClient client) {
//这里重写了IPerson_Logic中的定义,相当于bo中的override
return client.ClientID;
}
}
下面演示了如何为collection属性返回值:
[DomainComponent]
public interface IOrder {
[NonPersistentDc]
IList<IOrderLine> OrderLines { get; }
}
[DomainLogic(typeof(IOrder))]
public class OrderLogic {
public IList<IOrderLine> Get_OrderLines(IOrder order) {
//...
}
}
下面的IUser并不是一个DC定义(没用[DomainComponent]来定义,这时,必须在逻辑中为IsActive和UserName两个属性的实现。否则是不能运行通过的。
public interface IUser {
bool IsActive { get; set; }
string UserName { get; }
}
[DomainComponent]
public interface IPerson : IUser {
string LastName { get; set; }
string FirstName { get; set; }
}
在程序集包含DC组件时,可以通过过 ITypesInfo.RegisterEntity 方法来注册,你也可以通过 ITypesInfo.RegisterDomainLogic 和 ITypesInfo.UnregisterDomainLogic 的方法手动注册逻辑,当你不能访问DC Logic类来源,但需要操作DC逻辑分配时这很有用。
六、一对多和多对多关系的定义
在DC中,你不需要使用 Association来定义一对多和多对多关系.下面的代码片段演示了如何定义订单与订单明细关系.
[DomainComponent]
public interface IOrder {
IList<IOrderItem> Items { get; }
}
[DomainComponent]
public interface IOrderItem {
IOrder Order { get; set; }
}
下面是多对多关系:
[DomainComponent]
public interface IEmployee {
IList<ITask> Tasks { get; }
}
[DomainComponent]
public interface ITask {
IList<IEmployee> Employees { get; }
}
你可以只定义一端的属性,比如,IEmplyee.Tasks,另一端的,将会自动生成。当然在XAF的界面中,ITask.Employees将不会被显示出来。
下面的情况时,生成器不知道该如何生成代码,所以需要BackReferenceProperty来指定对方的属性:
[DomainComponent]
public interface IAccount {
[BackReferenceProperty("AccountOne")]
IList<IContact> ContactA { get; }
[BackReferenceProperty("AccountTwo")]
IList<IContact> ContactB { get; }
IList<IContact> ContactC { get; }
}
[DomainComponent]
public interface IContact {
string Name { get; set; }
IAccount AccountOne { get; set; }
IAccount AccountTwo { get; set; }
IAccount AccountThree { get; set; }
}
七、Shared Parts
当一个DC被几个DC同时继承时,这个DC必须要注册为SharePart,使用ITypesInfo.RegisterSharedPart 方法完成.
[DomainComponent]
public interface IWorker { } [DomainComponent]
public interface IManager : IWorker { } [DomainComponent]
public interface IEvangelist : IWorker { } public class MyModule : ModuleBase {
// ...
public override void Setup(XafApplication application) {
base.Setup(application);
XafTypesInfo.Instance.RegisterEntity("Manager", typeof(IManager));
XafTypesInfo.Instance.RegisterEntity("Evangelist", typeof(IEvangelist));
XafTypesInfo.Instance.RegisterSharedPart(typeof(IWorker)); //<-----这里
}
}
八、DC特有的Attribute
除了XAF中在BO中使用的Attribute,DC又增加了几个Attribute:
| Attribute | 说明 |
|---|---|
| BackReferencePropertyAttribute | 前面已经看到了,是用来明确的指定对方属性的。 |
| CreateInstanceAttribute | Applied to methods. Specifies that a Domain Component's target method will create Domain Component instances. |
| DomainComponentAttribute | 用了这个,接口才叫DC。 |
| DomainLogicAttribute | DC逻辑类标识。 |
| NonPersistentDcAttribute | 非持久化的DC,使用时也需要标识上DomainComponentAttribute |
| PersistentDcAttribute | 与BO中的PersistentAttribute 是一样的。可以指定一个表名。 |
《完》
XAF-Domain Components 技术 使用接口来定义ORM业务对象的更多相关文章
- 基于国内某云的 Domain Fronting 技术实践
发布时间:2019-12-16 11:30:53 一.简介 Domain Fronting,中文译名 “域前置” 或 “域名前置”,是一种用于隐藏真实C2服务器IP且同时能伪装为与高信誉域名通信的技术 ...
- 毕业论文中使用的技术—FileReader接口
用来把文件读入内存,并且读取文件中的数据. FileReader接口提供了一个异步API,使用该API可以在浏览器主线程中异步访问文件系统,读取文件中的数据 FileReader接口的方法 方法名 参 ...
- 【原创】Odoo开发文档学习之:ORM API接口(ORM API)(边Google翻译边学习)
官方ORM API开发文档:https://www.odoo.com/documentation/10.0/reference/orm.html Recordsets(记录集) New in vers ...
- xaf.domain object new 在属性上的用法
有如下业务对象定义: using System; using System.Linq; using System.Text; using DevExpress.Xpo; using DevExpres ...
- 利用open live writer工具的Metaweblog技术API接口同步到多个博客。
测试例子内容: hello world hello metaweblog hello open live writer
- 基于.NET的微软ORM框架视频教程(Entity Framework技术)
基于.NET的微软ORM框架视频教程(Entity Framework技术) 第一讲 ORM映射 第二讲 初识EntifyFramework框架 第三讲 LINQ表达式查询 第四讲 LINQ方法查询 ...
- 实现简单的PHP接口,以及使用js/jquery ajax技术调用此接口
主要介绍下如何编写简单的php接口,以及使用js/jquery的ajax技术调用此接口. Php接口文件(check.php): <?php $jsonp_supporter = $_GET[‘ ...
- 【安全研究】Domain fronting域名前置网络攻击技术
出品|MS08067实验室(www.ms08067.com) 千里百科 Domain Fronting基于HTTPS通用规避技术,也被称为域前端网络攻击技术.这是一种用来隐藏Metasploit,Co ...
- 是时候改变你的开发方式了-XAF信息系统快速框架介绍
我是一名.Net开发者,从DOS时代Turbo c 算起(1996年),马上满20年了.想想写过的代码真是不少,却做了很多重复反复的编码工作.当然中间也带过团队做过几个大项目,但是代码仍没写够,还是每 ...
随机推荐
- VC++.Net CAD编程架构
1.每个对应的菜单项的图形抽象的, 图形抽象基类, 取决于改变来自子(如矩形.椭圆形) 2.在Doc对象管理列表管理,图形对象,当图形需要重绘或序列存储,通过遍历该列表的对象可以是 3. 每个类的职责 ...
- selenium2入门 用Yaml文件进行元素管理 (五)
比如界面有一个按钮,id号是test.如果进行对象化的话,就是test.click就可以了.不用每次都要去创建test对象.如果id号变了,我们也只需要改一下test的名称就行了. 使用Yaml需要用 ...
- PHP 8: PHP的运算符
原文:PHP 8: PHP的运算符 本章将介绍PHP的运算符.运算符这个问题在每种语言里都有,因为我们已经熟悉了编程语言里的一种或是多种,所以只需要了解一下就行了.概括一下吧.PHP运算符有很多种,看 ...
- Mybatis之动态构建SQL语句
今天一个新同事问我,我知道如何利用XML的方式来构建动态SQL,可是Mybatis是否能够利用注解完成动态SQL的构建呢?!!答案是肯定的,MyBatis 提供了注解,@InsertProvider, ...
- Samba(一)通过Samba搭建Linux文件服务器
本文的目的是为了快速搭建一个linux文件服务器,主要是便于局域网电脑可以方便快速的获得Linux服务器共享的文档(非互传) samba是一个功能十分强大的软件,今天是我们的主角,因为本文是一个演示实 ...
- Memcache存储大量数据的问题
Memcache存储大数据的问题 huangguisu Memcached存储单个item最大数据是在1MB内,假设数据超过1M,存取set和get是都是返回false,并且引起性能的问题. 我们之 ...
- Android Wear和二维码
这是一篇发布在Android官方开发者社区博客,15年年初的时候就看到了这篇文章,直到现在才有时间把它翻译下来. 这是一篇如何在Android Wear上面如何正确地展示二维码的文章,里面有许多的经验 ...
- ASP.NET SignalR 2.0入门指南
ASP.NET SignalR 2.0入门指南 介绍SignalR ASP.NET SignalR 是一个为 ASP.NET 开发人员的库,简化了将实时 web 功能添加到应用程序的过程.实时Web功 ...
- ORACLE总结系列1--network文件夹里的admin的三个文件信息
sqlnet.ora 作用类似于linux或者其他unix的 nsswitch.conf文件,通过这个文件来决定怎么样找一个连接中出现的连接字符串(connect descriptor) 假如sqln ...
- BEncoding的编码与解码
BEncoding的编码与解码 1. BEncoding规则 BEncoding是BitTorrent用在传输数据结构的编码方式,我们最熟悉的“种子”文件,它里面的元数据就是 BEncoding ...