帮酷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  |  如果智培  |  酷兔英语