帮酷LOGO
0 0 评论
  • 显示原文与译文双语对照的内容
文章标签:IMP  WCF  Raven  Implementation  Ravendb  


PreviousNext
第十四章第XVI章

系列

WCF示例是一系列文章,描述如何使用WCF設計和開發一個用於通信和 NHibernate的WPF客戶機。 系列介紹描述了文章的範圍,並在高層次上討論了架構師解決方案。 系列的源代碼在 CodePlex 找到。 本系列文章介紹了RavenDB的持久性目的。

章節概述

對於這些新系列的這些新的組件,of解決方案的持久組件是圍繞工作和存儲庫模式設計。 TransManager 負責工作實現單元,因這裡它提供訪問 IRepositoryLocator的訪問許可權,從而訪問單個實體存儲庫。 存儲庫基於通過存儲庫定位器需要創建的泛型實現。 這些通用存儲庫向持久性Linq提供程序利用的IQueryble 方法公開基本的CRUD方法和端點

下面是在伺服器組件中使用的代碼的示例:

public CustomerDto UpdateCustomer(CustomerDto dto)
 {01return ExecuteCommand(locator => UpdateCustomerCommand(locator, dto));
 }
 private CustomerDto UpdateCustomerCommand(IRepositoryLocator locator, CustomerDto dto)
 {02var instance = locator.GetById<customer>(dto.Id);03 instance.Update(locator, dto); 
 return Customer_to_Dto(instance);
 } 

行 01: 用於更新現有實例的客戶服務入口點

使用行:使用Locator屬性來解決客戶實例

收費行:然後我們委託到域類來更新自己傳遞定位器和Dto實例

到本章,我們已經看到了持久性組件的兩個實現: 內存和 NHibernate 在本章中我們將介紹一個新的實現: RavenDB。

RavenDB 是一個文檔定位資料庫,可以方便對象的持久性。 在 NHibernate 中,實體類和資料庫表之間需要映射。 但是在RavenDB中,對於實體和持久框架之間的額外映射沒有這樣的需求。

本文討論了實現一組自定義組件的簡易性,以便eDirectory應用程序可以保存和讀取RavenDB文檔存儲庫中的對象。 我們在這個示例中使用嵌入式文檔存儲實現,我們還將討論如何將它設置為在內存內模式中執行測試。

我認為這不是在本系列中一直沿用的一個結果,因此我決定不更改本系列迄今為止使用過的域實體,這是一個很好的方法。 不過,本文應該是如何讓RavenDB工作的一個很好的。

不同代碼的情況下,使用Linq提供程序和通用存儲庫可能需要在較複雜的方案中使用這裡方法。

除了提到的約束之外,本文中提到的架構在許多情況下可以能很好,或者至少在你的項目中使用。

一個新項目被添加到名為 eDirectory.RavenDB的eDirectory解決方案中。 然後使用NuGet獲取對 RavenDB嵌入的引用。 值得注意的是,添加了post構建事件,因此所有構建構件都被複制到libs文件夾中,以便在客戶端項目中使用。

RavenDB知識庫

存儲庫實現與 NHibernate 在許多方面非常類似:

publicclass RepositoryRavenDB<TEntity>
 : IRepository<TEntity>
{
 privatereadonly IDocumentSession _sessionInstance;
 privatereadonlystring _idPrefix;
 public RepositoryRavenDB(IDocumentSession session)
 {
 _sessionInstance = session;01 _idPrefix = GetPrefix();
 }
 privatestaticstring GetPrefix()
 {
 var typeName = typeof (TEntity).Name;
 var flag = typeName.Last().Equals('s');02return typeName +
 (flag
? "es/" : "s/");
 }
 #region Implementation of IRepository<TEntity>public TEntity Save(TEntity instance)
 { 03 _sessionInstance.Store(instance);
 return instance;
 }
 publicvoid Update(TEntity instance)
 {
 }
 publicvoid Remove(TEntity instance)
 {04 _sessionInstance.Delete(instance);
 }
 public TEntity GetById(long id)
 {05return _sessionInstance.Load<TEntity>(_idPrefix + id);
 }
 public IQueryable<TEntity> FindAll()
 {06return _sessionInstance.Query<TEntity>();
 }
 #endregion}

對每一個倉庫/實體類型進行收費,以供 Load 方法使用。

以複數結尾的行 02行:前綴以複數結束,以entity需要額外檢查的實體名稱,

第三行第1 行:當調用 Store 方法時,新實例將保存在RavenDB中,這不需要額外的映射,這是一個很酷的特性。 另外,RavenDB通過 NAME 約定在我們的實體中檢測Id屬性,並且在返回方法后填充該屬性

行 04: Delete 方法用於從資料庫中刪除實體

收費的第 05行:Load 方法是通過Id檢索實體的優化機制,這就是前綴需要使用的地方

收費第 06行:FindAll 方法委託給 RavenDB Linq提供者,與在 NHibernate 實現中完成的完全相同

另外要注意的是,RavenDB實現中不需要更新方法。

存儲庫定位器

定位器實現非常簡單,我們之前看到的非常相同:

publicclass RepositoryLocatorRavenDB
 : RepositoryLocatorBase, IResetable, IStoreInitialiser
{
 privatereadonly IDocumentSession _sessionInstance;
 public RepositoryLocatorRavenDB(IDocumentSession session)
 {
 _sessionInstance = session;
 }
 #region Overrides of RepositoryLocatorBaseprotectedoverride IRepository<T> CreateRepository<T>()
 {01returnnew RepositoryRavenDB<T>(_sessionInstance);
 }
 #endregion#region Implementation of IResetable02. . . 
 #endregion#region Implementation of IStoreInitialiser02. . .
 #endregion}

計算行:基定位器類調用這裡方法來獲取給定類型的存儲庫實例

這段代碼只是為了測試原因而忽略的,本文稍後將在本文中討論它們

事務管理器

同樣,此類的實現與 NHibernate的實現非常類似:

publicclass TransManagerRavenDB
 : TransManagerBase
{
 privatereadonly IDocumentSession _sessionInstance;
 public TransManagerRavenDB(IDocumentSession session)
 {
 _sessionInstance = session;01 Locator = new RepositoryLocatorRavenDB(_sessionInstance);
 }
 #region Overriden Base Methodspublicoverridevoid CommitTransaction()
 {
 base.CommitTransaction();02 _sessionInstance.SaveChanges();
 }
 publicoverridevoid Rollback()
 {
 base.Rollback();03 _sessionInstance.Advanced.Clear();
 }
 protectedoverridevoid Dispose(bool disposing)
 {
. . .
 }
 privatevoid Close()
 {
. . .
 }
 #endregion}

在構造函數中傳遞行:IDocumentSession 被傳遞到創建 RepositoryLocatorRavenDB的構造函數中

第三行第1 行:提交事務管理器創建的所有更改,我們需要在事務管理器中調用該方法。

如果需要回滾,則使用行 03來放棄所有的更改

沒有什麼特別的機制,沒有一個特定的機制啟動事務,如我們在 NHibernate 中。

事務管理器工廠

這裡組件負責兩個關鍵角色,IDocumentSessionTransManager的創建:

publicclass TransManagerFactoryRavenDB
 : ITransFactory
 {
 private IDocumentStore _documentStore;
 private IDocumentStore DocumentStore
 {
 get {03if (_documentStore!= null) return _documentStore;
 _documentStore = InitialiseDocumentStore();
 return _documentStore;
 }
 }
 private IDocumentStore InitialiseDocumentStore()
 {
 var store = new EmbeddableDocumentStore { DataDirectory = "eDirectory" };01 store.Initialize();
 return store;
 }
 #region Implementation of ITransFactorypublic ITransManager CreateManager()
 {02returnnew TransManagerRavenDB(DocumentStore.OpenSession());
 }
 #endregion }

收費的第1 行:創建一個名為"eDirectory"的可以嵌入文檔存儲實例,這將在部署文件夾上。 Initialize方法在對存儲調用任何操作之前是至關重要的。

收費行:這是返回事務管理器的工廠方法,將新會話傳遞到它的構造函數。 NHibernate 一樣,這個會話實例除了定位器和存儲庫之外,在代碼中不可用。 這是使工作單元正常工作的關鍵方面。

收費的第1 行:你可能希望增強這裡方法以避免爭用條件,例如文檔存儲的延遲初始化將是最好的。

如何配置客戶端用戶界面

要讓WPF客戶端使用 RavenDB,請按以下說明操作:

  • 確保所有項目都正確生成,你可能希望手動刪除調試或者發布文件夾中的所有文件
  • 修改客戶端( edirectory.wpf ) 中的App.config,以便將SpringConfigFile設置為: file://RavenDBConfiguration.xml
  • 執行客戶端項目
  • 使用address地址視圖customer創建新的客戶'

此時,創建第一個客戶實例后,你可能會得到一個類似下面這樣的空網格:

我們創建第一個客戶:

按下保存按鈕后,客戶網格為空:

如果等待 10 -15秒,然後刷新命令按鈕,則會顯示客戶記錄:

我們所複製的內容是RavenDB中的舊索引狀態,當第一次在RavenDB存儲實例中創建時,索引不會返回。 值得注意的是,刷新是在另一個請求中完成的,即保存操作,在本例中,

如果關閉應用程序並再次重新啟動該應用程序,就會發現這個問題不再發生。 你可能想看看關於這個'功能'的官方文檔。 我們將在測試部分再次討論它,看看如何避免這種情況。

其他方面

在域實體中需要一個額外的變化,我們需要用arraylist屬性標記客戶和地址實體,使NewtonSoft庫能正確序列化對象。 我們的Linq查詢中還有一個更改,它的中必須由'=='替換'等於';如果使用'等於'方法,則 RavenDB Linq爭用。

使用RavenDB進行測試

如果要在運行測試時使用 RavenDB,有一個關鍵方面需要考慮:

  • 在測試執行之間刪除資料庫

內存內存

但是在討論如何拆除文檔存儲之前,有一個值得注意的特性: 可以將RavenDb配置為在內存中運行,從而提高性能,而不會丟失任何行為/功能。 因此,我修改了 TransManagerFactoryRavenDB,以便在內存中運行測試:

publicclass TransManagerFactoryRavenDB
 : ITransFactory
 {
. . .01privatebool IsSetForTesting { get; set; }
 private IDocumentStore InitialiseDocumentStore()
 {
 var store =
 IsSetForTesting02? new EmbeddableDocumentStore
 {
 RunInMemory = true }
 : new EmbeddableDocumentStore {DataDirectory = "eDirectory"};
 store.Initialize();
 return store;
 }
. . .
 }

行 01: 可以設置一個新標誌,指示必須創建內存內實例

如果設置了 flag,則在內存中創建RavenDB實例

用於測試的spring 配置文件設置 IsSetForTesting 屬性,因此在執行測試時,將使用內存的RavenDB實例。 你可能希望查看位於測試項目中的TestRavenDBConfiguration 文件以獲得更詳細的信息。

向下拆

在測試過程中,我使用了來自 blog博客的索引,因此在測試期間創建實體實例時,可以使用定製的索引刪除這些實例。 通過從 AbstractIndexCreationTask 類繼承,在代碼中創建RavenDB索引:

publicclass AllDocumentsById : AbstractIndexCreationTask
 {
 publicconststring Name = "AllDocumentsById";
 #region Overrides of AbstractIndexCreationTaskpublicoverride IndexDefinition CreateIndexDefinition()
 {
 returnnew IndexDefinition
 {01 Name = AllDocumentsById.Name,02 Map = "from doc in docs let DocId = doc["@metadata"]["@id"] select new {DocId};" 
 }; 
 }
#endregion}

我們將指數為已知的NAME,當需要刪除實體時,我們需要它。

計算行:聲明索引映射,以便為在存儲中創建的任何文檔創建條目。

如果希望創建索引,測試項目有一些額外功能來確定是否實現了介面,如果是這樣,則調用 ConfigureStore 方法。 RepositoryLocatorRavenDB 這樣做:

publicclass RepositoryLocatorRavenDB01 : RepositoryLocatorBase, IResetable, IStoreInitialiser
 {
. . .
 #region Implementation of IStoreInitialiserpublicvoid ConfigureStore()
 {
 var documentStore = _sessionInstance.Advanced.DocumentStore as EmbeddableDocumentStore;
 if (documentStore == null) return;02 IndexCreation.CreateIndexes(typeof(AllDocumentsById).Assembly, documentStore);
 }
 #endregion }

那麼,測試如何使用索引。 但是,RepositoryLocatorRavenDB 也實現了 IResetable 介面:

publicclass RepositoryLocatorRavenDB
 : RepositoryLocatorBase, IResetable, IStoreInitialiser
 {
. . .
 #region Implementation of IResetablepublicvoid Reset()
 {
 var documentStore = _sessionInstance.Advanced.DocumentStore as EmbeddableDocumentStore;
 if (documentStore == null) return;01while (documentStore.DatabaseCommands.GetStatistics().StaleIndexes.Length!= 0)
 {
 Thread.Sleep(10);
 }02 _sessionInstance.Advanced.DatabaseCommands.DeleteByIndex(AllDocumentsById.Name, new IndexQuery());
 }
 #endregion. . .
 }

我將在第二行介紹行。

行 02: 它使用了我們定製索引的NAME 傳遞的值。

上索引有問題: 當測試執行只創建一個實體實例時,AllDocumentsById 索引是過時的。 如果創建了多個實例,則似乎解決了問題。 因這裡,第 01行用於確保在調用刪除方法時索引不是過時的。

將配置設置為使用 RavenDB

在運行測試時使用RavenDB實現,確保配置了 App.config,以便將 SpringConfigFile appSetting設置為 TestRavenDBConfiguration.xml:

結束語

實際上,它很容易調整 RavenDB,實際上需要幾個小時才能使測試工作得更加時間。 不是 Having 在域實體和文檔存儲之間創建映射,這使得。

注意:如果在設計RavenDB存儲域時遵循最佳設計實踐,則需要離開傳統的關係方法。 簡言之,在域術語中,文檔成為聚合,而複製不是'sin'。 如果你使用的是 NHibernate 或者它的他任何ORM框架,那麼這種思考方式是根本的改變。

其他資源鏈接



文章标签:IMP  Implementation  WCF  Raven  Ravendb  

Copyright © 2011 HelpLib All rights reserved.    知识分享协议 京ICP备05059198号-3  |  如果智培  |  酷兔英语