XAF-Domain Components 技術 使用接口來定義ORM業務對象

1、簡介 

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不能添加自定義字段

 


 

 2、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中實現.數據庫


 

3、註冊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的其它重載方法。express

 


 

4、Domain Logic

 

每一個DC能夠有一(零)個或多個Domain Logic. Domain Logic 是一個普通的類,加上了 DomainLogicAttribute 標記, 並指定DC類型. 其實再多的話都沒有一個代碼實例有用:app

 

複製代碼
[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類。ide

那麼,DC中的語法到底有多少呢?ui

說明 示例

Get_屬性名稱this

當property的get被調用時,就執行這個方法。
若是屬性是隻有get或,非持久化時,才能夠實現這個,不然都自動實現。spa

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

Set_屬性名設計

當property的set被調用時,就執行這個方法。
屬性必須不能是隻讀的,即,DC中聲明瞭set,使用這個方法實現非持久化屬性。code

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操做.

 

5、示例:

以前的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邏輯分配時這很有用

 


 

6、一對多和多對多關係的定義

 

在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; }
}
複製代碼

 

 


 

7、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));   //<-----這裏
    }
}
複製代碼

 


 

8、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 是同樣的。能夠指定一個表名。
相關文章
相關標籤/搜索