一、简介

Domain Component组件技术,以下简称DC,是扩展自XPO的, 官方不建议新手使用DC。
如果你用过EF,XPO及类似的ORM,这是很容易理解的,DC是基于XPO的,只是原来定义ORM对象时用的是类,现在改用接口
然后通过DC上声明的一些Attribute来生成最终的类代码,在运行时编译,最终还是生成了xpo的类。
 
当然接口只是可定义一些结构,方法,属性及一些个性化的逻辑并没有实现,再使用一个Logic类,来做真正的实现。对于一些默认的读写功能的属性,不需要在logic类中实现。DC机制会默认生成一个实现。
 
  • 可以创建可重用的领域对象:多数情况下,每个XAF中用到的领域对象都不是唯一的,比较常见的对如:人、电话、地址,等领域对象,这些使用频率较高的,想要抽象出来还是有点难度的,这不是一个简单的任务,使用DC这事就简单了。
  • 可以使用多重继承:因为DC是用接口描述的,所以,多继承在C#的语法级别被支持,你可以使用继承以前写过的DC,重用它,并且可以增加新的属性和替换逻辑。事实上,这是我最喜欢的一个特性!
  • 需要持久性化基类继承实现领域对象 :最终的执行代码是生成的,这当然很容易实现了。当然,也可以指定基类。
 
  注意:
  • DC组件技术不支持Model First和Database first的方式。我们不推荐使用附加(就是两个或多个)数据库。因此,我们不提供任何手段从现有数据库生成域组件代码和逻辑,我们有没有立即的计划来支持此方案。请试试 XPO 或实体框架数据模型。
  • 自定义字段不能在设计时添加到域组件。
  • 如果一个DC组件注册为SharePart,不能添加自定义字段。

二、DC定义

 下面的代码片段演示如何定义一个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, 给接口上加上 NavigationItemAttributeFullName 被定义为只读的.它需要在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被调用时,就执行这个方法。
如果属性是只有get或,非持久化时,才可以实现这个,否则都自动实现。

public static string Get_FullName(IMyInterface instance)
public static string Get_FullName(IMyInterface instance, IObjectSpace objectSpace)

Set_属性名

当property的set被调用时,就执行这个方法。
属性必须不能是只读的,即,DC中声明了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_interfacesource_parameters)
    当前DC类型,指当前对象和接口中定义的那些参数.
  • LogicMethodName(target_interfaceobject_spacesource_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业务对象的更多相关文章

  1. 基于国内某云的 Domain Fronting 技术实践

    发布时间:2019-12-16 11:30:53 一.简介 Domain Fronting,中文译名 “域前置” 或 “域名前置”,是一种用于隐藏真实C2服务器IP且同时能伪装为与高信誉域名通信的技术 ...

  2. 毕业论文中使用的技术—FileReader接口

    用来把文件读入内存,并且读取文件中的数据. FileReader接口提供了一个异步API,使用该API可以在浏览器主线程中异步访问文件系统,读取文件中的数据 FileReader接口的方法 方法名 参 ...

  3. 【原创】Odoo开发文档学习之:ORM API接口(ORM API)(边Google翻译边学习)

    官方ORM API开发文档:https://www.odoo.com/documentation/10.0/reference/orm.html Recordsets(记录集) New in vers ...

  4. xaf.domain object new 在属性上的用法

    有如下业务对象定义: using System; using System.Linq; using System.Text; using DevExpress.Xpo; using DevExpres ...

  5. 利用open live writer工具的Metaweblog技术API接口同步到多个博客。

    测试例子内容: hello world hello metaweblog hello open live writer

  6. 基于.NET的微软ORM框架视频教程(Entity Framework技术)

    基于.NET的微软ORM框架视频教程(Entity Framework技术) 第一讲  ORM映射 第二讲 初识EntifyFramework框架 第三讲 LINQ表达式查询 第四讲 LINQ方法查询 ...

  7. 实现简单的PHP接口,以及使用js/jquery ajax技术调用此接口

    主要介绍下如何编写简单的php接口,以及使用js/jquery的ajax技术调用此接口. Php接口文件(check.php): <?php $jsonp_supporter = $_GET[‘ ...

  8. 【安全研究】Domain fronting域名前置网络攻击技术

    出品|MS08067实验室(www.ms08067.com) 千里百科 Domain Fronting基于HTTPS通用规避技术,也被称为域前端网络攻击技术.这是一种用来隐藏Metasploit,Co ...

  9. 是时候改变你的开发方式了-XAF信息系统快速框架介绍

    我是一名.Net开发者,从DOS时代Turbo c 算起(1996年),马上满20年了.想想写过的代码真是不少,却做了很多重复反复的编码工作.当然中间也带过团队做过几个大项目,但是代码仍没写够,还是每 ...

随机推荐

  1. OpenGL+VS2013+WIN7(64)组态

    1.下载windows在下面glut安装文件:http://www.opengl.org/resources/libraries/glut/glutdlls37beta.zip 2. 拆开发现五个文件 ...

  2. List<string>和string[]

    List<string>和string[] List<string>是集合:string[]是数组: ///////////////////////////////////// ...

  3. 安装Windows2008操作系统 - 初学者系列 - 学习者系列文章

    Windows2008这款服务器操作系统不知道有多少服务器在使用,毕竟前面有经典的2003系统,后续有2012操作系统.具体就不讨论这些了.下面就对Windows2008服务器操作系统的安装进行介绍. ...

  4. jquery-validate的用法

    默认校验规则 (1)required:true               必输字段(2)remote:"check.php"          使用ajax方法调用check.p ...

  5. MySql 集群配置

    MYSQL CLUSTER方案介绍 本文的大致框架来自罗志威.黄川的报告, 在它的基础上进行简化和修改一些bug并且添加了主从复制的章节,最后做出该文档 MySQL Cluster 是MySQL适合于 ...

  6. ModelBinder——ASP.NET MVC Model绑定的核心

    ModelBinder——ASP.NET MVC Model绑定的核心 Model的绑定体现在从当前请求提取相应的数据绑定到目标Action方法的参数.通过前面的介绍我们知道Action方法的参数通过 ...

  7. WebApi HttpMsgHanler的执行顺序

    原来忘记在哪个大牛的博客上看到的,说添加顺序与执行顺序是相反的,事实在下边:直接上代码: //STEP10,不论如何先记录下来请求信息 if (msgHandlerSettings.LoggingHa ...

  8. Binder机制,从Java到C (4. Parcel)

    1. 远程调用的数据传输 在远程的函數中,必然会需要传递一些数据,那这些数据是怎么传输的呢? 在IPC中,Proxy端的作用就是将一些参数打包,然后发送出去,下面是在Proxy端经常会遇见的调用远程方 ...

  9. CGI杂谈

    CGI是一个连接外部应用程序到信息服务器(比如HTTP或者网络服务器)的标准.一个简单的HTML文档是无交互后台程序,它是静态的,也就是说它处于一个不可变的状态,即文本文件不可以变化.相反地,CGI程 ...

  10. 基于多重信号分类算法的DOA估计

    原创博文,转载请注明出处 下面的论文是我的雷达处理的作业,拿来共享,不喜勿喷.由于公式编辑器的原因,无法复制公式,全部内容请点击. 基于多重信号分类算法的DOA估计 1引言 多重信号分类(MUSIC) ...