程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 關於ActiveRecord、領域模型以及iBatis的種種想法

關於ActiveRecord、領域模型以及iBatis的種種想法

編輯:C#入門知識

首先,我想說明的這是一篇純意識流的文章,

想到哪裡說到哪裡。有強烈數據結構、流程邏輯控的博友可以略過……

 

關於ActiveRecord、領域模型以及iBatis的種種想法

 

最近看了面向領域的種種爭論,基於ActiveRecord的設計模式確實能將DAO(Data Access Object)對象、DTO (Data Transfer Object)對象和DMO Service (Domain Model Service Object)很自然的合並到一個繼承自ActiveRecordBase的子類中。

 

如 DMO對象 PersonBase { public string Name { get; set; } public  int Age {get; set;} public  string State {get;set;} }

而後將這個Person對象加上[ActiveRecord(Table="Persons")]就成為了一個繼承自ActiveRecordBase的DAO對象。

而後將其加上[DataContract]注解,就立馬成為了一個可供WCF(Windows Communication Foundation)進行傳輸的DTO(Data Transfer Object)。到此時,這個PersonBase對象只是一個人的原型。具有一些人的屬性,如年齡和姓名還有狀態。但是這個時候的他還只是個嬰兒,除了能設置它的屬性、持久化進數據庫外什麼也做不了。

然後新建Person擴展自PersonBase擴展兩個方法:Cry和 StopCry

Person :  PersonBase, IPersonService

  public PersonBase Cry(PersonBase person == null)

  {

    if(person == null)

    {

      this.State = "Crying";

    }

    {

      person.State = "Crying";

    }

    this.Update(); //此處調用繼承自ActiveRecord的Update方法來更新數據庫

    return this;

  } 

  public PersonBase StopCry(PersonBase person == null)

  {

    if(person == null)

    {

      this.State = "Normal";

    }

    {

      person.State = "Normal";

    }

    this.Update();

    return this;

  }

}

 

再建立Person的Interface

[ServiceContract]

public interface IPersonService 

{

  [OperationContract]

  PersonBase Cry(PersonBase person == null);

  [OperationContract]

  PersonBase StopCry(PersonBase person == null);

}

此時給這個具有行為能力的Person類具有Cry和StopCry兩種動作,此時通過WCF可以將此Person發布為一個Web Service或者是其他形式的WCF服務。

 

此時客戶端也可以共享Person這個類提供的服務。

通過WCF的ChannelFactory建立一個Proxy對象,在客戶端同時擴展這個對象也為Person,而且這個Person對象也繼承自服務端的PersonBase,同樣這個客戶端的Person類同樣實現了IPersonService接口

 

Person :  PersonBase, IPersonService

  public PersonBase Cry(PersonBase person == null)

  {

    PersonBase personback = proxy.Cry(this)

    this.State = personback.State;

    return personback;

  } 

  public PersonBase StopCry(PersonBase person == null)

  {

    PersonBase personback = proxy.Cry(this)

    this.State = personback.State;

    return personback;

  }

}

 

字樣就實現了一個Person類從DAO到DTO再到DMO Service的功能轉換。

其中的核心原則就是代碼重復最小化。增加類的復用性,從而避免一個項目同時維護著Data Access Object、Data Transfer Object、以及一個Rich Domain Model Object。

 

此處的Domain Object是一個含有Domain Model Data和Domain Model Service的富DMO對象。

不再貧血了。而且可以端進行簡單的繼承和重構。如上面例子中 客戶端仍然建立一個擴展自PersonBase這個POCO的Person類,而這個類同樣實現了IPersonService接口,同樣具有Cry和Stop這兩種行為。

 

只是服務端的Person是通過操作類本身,然進行相關的行為。

而客戶端的Person是通過WCF提供的proxy代理服務端的Person類的Cry及StopCry行為,並且需要將客戶端的Person類本身通過this引用作為參數傳遞給服務端的Service做相關處理,再將處理結果返回給客戶端。

可能聽起來比較拗口。但是想明白後還是好理解的。

 

至於服務端的Person類和客戶端的Person是兩個不同的類,為何能在服務端和客戶端進行傳遞呢?

答案就在PersonBase類。不管是服務端的Person類還是客戶端的Person類都繼承自公用的基類PersonBase。

而Person作為Service出現在服務端的時候,要求傳遞的DataContract參數為PersonBase類。根據子類能賦予給父類型引用的原則。理論上是可行的。

 

看到這裡,ActiveRecord在面向DMO面向領域的模式中的弊病想必大家看出來了吧。

看客們看到這裡也許要批評我了,我說了半天,壓根就不是Domain Model的面向領域模型嘛~ 瞎搞了。

 

首先說說我對面向領域的編程模型的理解吧:

我認為的Domain Model 是這樣的。比如對於一款進銷存軟件來說,對於銷售人員這個銷售領域。銷售領域關心的是銷售的價格,折扣,銷售的數量,營銷人員是誰。銷售提成多少等等。而對於進貨人員來說,它只關心進貨的價格,進貨的渠道,供貨商。而對於財務來說,它只關心這個月的銷售的金額、以及銷售成本和利潤等。

但是在數據庫中,可能就只表現為兩張表,一張是進貨表,一張是銷售表。

至於財務鎖關心的利潤,是通過數據庫執行相關的SQL語句來進行統計核算,比如統計這個月的銷售總額等等。

由於面向財務領域的數據並不真正存在於一個單獨的財務表中。因此如果此時再利用ActiveRecord進行財務的統計的時候,這個Domain Model Object就會產生問題了,它應該Mapping到哪個表呢?

 

由於ActiveRecord是基於NHibernate的二次封裝,Nhibernate又源於hibernate。

(PS:我對Castle ActiveRecord沒有怎麼深入的研究,但是我曾經參與過幾個基於hibernate的項目的開發,hibernate對於自定義 Sql語句的Mapping 到 Pojo 很麻煩,甚至說是違背了hibernate的核心思想)

 

與此同時並駕齊驅的輕量級SQL Mapping Object iBatis卻在這方面做的很好。

它能將任意的SQL查詢語句映射到自定義的Pojo上(.net為Poco)。

 

因此,很適合我上述的進銷存軟件的領域模型的開發。(通過編寫特定的SQL語句,用select sum(price * *discount * quantity) as TotalMoney .....諸如此類的語句,將特定語句查詢得到的TotalMoney這個字段映射到比如說 AccountingSum這個類的 public  int TotalMoney { get; set; } 屬性上。

甚至可以通過兩句sql語句的合並,同時完成某一個特定的領域行為。

如銷售行為:第一句,insert into Sales (ItemName,Price,Quantity) values (香皂, 100, 1);

      第二句,update Stock set Quantity = Quantity - 1 where ItemName = 香皂;

這樣的隱式SqlTransition來完成一個特定的領域行為。

 

所以我覺得,問題可能出在了這個上面:

無論是hibernate 還是 ibatis 都太固執了。

 

一個非得要面向 Table。將Table與Object綁定死(至少從默認的情況下,推薦Table Mapping To Object)

而另一個,卻是沒有綁定什麼 Table, 但是,卻什麼都需要寫Select xxx,yyy, * from table where xxxx = yyyy

對於簡單的從一張表根據Primary Key檢索出一條特定的Record都要寫一大堆的SQL語句

靈活性是好,可是有點啰嗦,不能像hibernate(ActiveRecord)那樣習慣大於約定。

而ActiveRecord(hibernate)又限制了太多的數據庫服務器的功能。

對於大批量數據的歸納統計,SQL語句因為其內部運算優勢以及相關的語句優化。它的效率要比用hibernate一條一條的遍歷數據本身然後做出統計的效率高得高。

 

如:

decimal totalmoney = 0.00M:

foreach(GoodItem item in GoodItemQueryList)

{

  totalmoney += item.Price * item.Discount * item.Quantiy;

}

SQL語句

select sum(price * discount * quantity) from GoodItem where ... 

 

這兩種實現方式雖然都能實現相同得功能,但是我像連新手也能看得出在性能優勢上孰優熟略

首先從SqlClient與SqlServer的數據量上來看,明顯第一種會在數據庫客戶端和服務器產生大量的數據交流

 

因此,在此處我像表明的是。

ibatis很好,hibernate不錯。

但是如果能將兩者CrossFire起來,那就火力相當十足啦。(此時我想到了我的上海Volks Wagen CrossPolo,很小很強大!)

 

ActiveRecord(Hibernate)把SQL Server服務器的功能只用了一般,或者說,大多數用Hibernate的人受其核心思想影響,

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