一、簡介
- 可以創建可重用的領域對象:多數情況下,每個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
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 是一樣的。可以指定一個表名。 |
《完》
文章列表