一、简介

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. VC++.Net CAD编程架构

    1.每个对应的菜单项的图形抽象的, 图形抽象基类, 取决于改变来自子(如矩形.椭圆形) 2.在Doc对象管理列表管理,图形对象,当图形需要重绘或序列存储,通过遍历该列表的对象可以是 3. 每个类的职责 ...

  2. selenium2入门 用Yaml文件进行元素管理 (五)

    比如界面有一个按钮,id号是test.如果进行对象化的话,就是test.click就可以了.不用每次都要去创建test对象.如果id号变了,我们也只需要改一下test的名称就行了. 使用Yaml需要用 ...

  3. PHP 8: PHP的运算符

    原文:PHP 8: PHP的运算符 本章将介绍PHP的运算符.运算符这个问题在每种语言里都有,因为我们已经熟悉了编程语言里的一种或是多种,所以只需要了解一下就行了.概括一下吧.PHP运算符有很多种,看 ...

  4. Mybatis之动态构建SQL语句

    今天一个新同事问我,我知道如何利用XML的方式来构建动态SQL,可是Mybatis是否能够利用注解完成动态SQL的构建呢?!!答案是肯定的,MyBatis 提供了注解,@InsertProvider, ...

  5. Samba(一)通过Samba搭建Linux文件服务器

    本文的目的是为了快速搭建一个linux文件服务器,主要是便于局域网电脑可以方便快速的获得Linux服务器共享的文档(非互传) samba是一个功能十分强大的软件,今天是我们的主角,因为本文是一个演示实 ...

  6. Memcache存储大量数据的问题

    Memcache存储大数据的问题  huangguisu Memcached存储单个item最大数据是在1MB内,假设数据超过1M,存取set和get是都是返回false,并且引起性能的问题. 我们之 ...

  7. Android Wear和二维码

    这是一篇发布在Android官方开发者社区博客,15年年初的时候就看到了这篇文章,直到现在才有时间把它翻译下来. 这是一篇如何在Android Wear上面如何正确地展示二维码的文章,里面有许多的经验 ...

  8. ASP.NET SignalR 2.0入门指南

    ASP.NET SignalR 2.0入门指南 介绍SignalR ASP.NET SignalR 是一个为 ASP.NET 开发人员的库,简化了将实时 web 功能添加到应用程序的过程.实时Web功 ...

  9. ORACLE总结系列1--network文件夹里的admin的三个文件信息

    sqlnet.ora 作用类似于linux或者其他unix的 nsswitch.conf文件,通过这个文件来决定怎么样找一个连接中出现的连接字符串(connect descriptor) 假如sqln ...

  10. BEncoding的编码与解码

    BEncoding的编码与解码   1. BEncoding规则 BEncoding是BitTorrent用在传输数据结构的编码方式,我们最熟悉的“种子”文件,它里面的元数据就是 BEncoding ...