程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> XAF-Domain Components 技術 使用接口來定義ORM業務對象,xaf-domainorm

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

編輯:關於.NET

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


一、簡介 

Domain Component組件技術,以下簡稱DC,是擴展自XPO的, 官方不建議新手使用DC。 如果你用過EF,XPO及類似的ORM,這是很容易理解的,DC是基於XPO的,只是原來定義ORM對象時用的是類,現在改用接口。 然後通過DC上聲明的一些Attribute來生成最終的類代碼,在運行時編譯,最終還是生成了xpo的類。   當然接口只是可定義一些結構,方法,屬性及一些個性化的邏輯並沒有實現,再使用一個Logic類,來做真正的實現。對於一些默認的讀寫功能的屬性,不需要在logic類中實現。DC機制會默認生成一個實現。  
  • 可以創建可重用的領域對象:多數情況下,每個XAF中用到的領域對象都不是唯一的,比較常見的對如:人、電話、地址,等領域對象,這些使用頻率較高的,想要抽象出來還是有點難度的,這不是一個簡單的任務,使用DC這事就簡單了。

  • 可以使用多重繼承:因為DC是用接口描述的,所以,多繼承在C#的語法級別被支持,你可以使用繼承以前寫過的DC,重用它,並且可以增加新的屬性和替換邏輯。事實上,這是我最喜歡的一個特性!

  • 需要持久性化基類繼承實現領域對象 :最終的執行代碼是生成的,這當然很容易實現了。當然,也可以指定基類。
    注意:
  • 在Medium Trust 環境中,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, 給接口上加上 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被調用時,就執行這個方法。
如果屬性是只有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 是一樣的。可以指定一個表名。

《完》

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved