3

我正计划使用 RavenDB 作为我的数据存储来构建单页应用程序 (SPA)。

我想从 SPA 部分的 ASP.NET Hot Towel 模板开始。

我将删除 EntityFramework/WebApi/Breeze 组件并替换为 RavenDB 用于存储和 ServiceStack 用于构建后端 API。

大多数当前观点似乎不赞成在 RavenDB 之上使用任何类型的存储库或额外的抽象,并要求直接在控制器内部使用 RavenDB API(在 MVC 应用程序中)

我假设在使用带有 ServiceStack 的 Raven 并直接在我的服务实现内部调用 IDocumentSession 时我应该遵循同样的智慧。

我担心的事实是,我的服务实现似乎会因为遵循这条路径而变得相当臃肿。似乎我经常需要多次编写相同的代码,例如,如果我需要在几个不同的 Web 服务端点中更新用户文档。

我似乎也可能需要从我的应用程序的其他(未来)部分访问 Raven。例如,我将来可能需要添加一个控制台应用程序来处理队列中的作业,而这部分应用程序可能需要访问 Raven 中的数据……但从一开始,我通往 Raven 的唯一途径就是通过网络服务 API。我只是打算从这个理论上的控制台应用程序调用 web api 吗?如果它们可能在相同的硬件上运行,似乎效率低下。

任何人都可以就如何在我的网络服务和其他地方有效利用 Raven 提供任何建议,同时在使用此文档存储时仍遵循最佳实践?创建一个中间业务逻辑层来直接处理对 raven 的调用似乎很实用……允许我的 web 服务调用该层内的方法。这有意义吗?

编辑

任何人都可以提供任何类似架构的最新样本吗?

4

2 回答 2

7

FWIW,我们目前正在使用 ServiceStack 和 RavenDB 开发应用程序。我们正在使用 DDD 方法,并将我们的业务逻辑放在丰富的领域层中。架构是:

  1. 网络应用程序。托管 Web 客户端代码 (SPA) 和服务层。

  2. 服务层。Web 服务使用 ServiceStack 和干净/相当扁平的 DTO,这些 DTO 与域对象完全分离。Web 服务负责管理事务和所有 RavenDB 交互。大多数“命令式”服务操作包括:a)加载由请求标识的域对象(文档),b)调用业务逻辑,c)将结果转换为响应 DTO。我们增强了 ServiceStack,因此许多命令式操作使用自动处理程序,无需任何代码即可完成上述所有操作。'Query-ish' 服务操作通常包括:a)对 RavenDB 执行查询,b)将查询结果转换为响应 DTO(实际上这通常作为 a 的一部分完成),在查询处理期间使用 RavenDB/指数/变压器)。

  3. 领域层。与 DDD 语言中的“根聚合”相对应的文档完全与数据库无关。他们对如何加载/保存等一无所知。域对象仅公开公共 GETTER 和私有 SETTER。修改域对象状态的唯一方法是调用方法。域对象公开旨在由服务层使用的公共方法,或在域层内使用的受保护/内部方法。域层引用 Messages 程序集,主要是为了允许域对象上的方法接受复杂的请求对象,并避免使用冗长的参数列表的方法。

  4. 消息汇编。支持其他本地 .Net 客户端的独立程序集,例如单元测试和集成测试。

至于其他客户,我们有两种选择。我们可以引用 ServiceStack.Common 和 Messages 程序集并调用 Web 服务。或者,如果需求大不相同并且我们希望绕过 Web 服务,我们可以创建一个新的客户端应用程序,引用域层程序集和 Raven 客户端并直接以这种方式工作。

在我看来,存储库模式是一种不必要且有漏洞的抽象。我们仍在开发中,但到目前为止,上述方法似乎运行良好。

编辑

一个大大简化的域对象可能看起来像这样。

public class Order
{
    public string Id { get; private set; }
    public DateTime Raised { get; private set; }
    public Money TotalValue { get; private set; }
    public Money TotalTax { get; private set; }
    public List<OrderItem> Items { get; private set; }

    // Available to the service layer.
    public Order(Messages.CreateOrder request, IOrderNumberGenerator numberGenerator, ITaxCalculator taxCalculator)
    {
        Raised = DateTime.UtcNow;
        Id = numberGenerator.Generate();
        Items = new List<OrderItem>();
        foreach(var item in request.InitialItems)
            AddOrderItem(item);
        UpdateTotals(taxCalculator);
    }

    private void AddOrderItemCore(Messages.AddOrderItem request)
    {
        Items.Add(new OrderItem(this, request));
    }

    // Available to the service layer.
    public void AddOrderItem(Messages.AddOrderItem request, ITaxCalculator taxCalculator)
    {
        AddOrderItemCore(request);
        UpdateTotals(taxCalculator);
    }

    private void UpdateTotals(ITaxCalculator taxCalculator)
    {
        TotalTax = Items.Sum(x => taxCalculator.Calculate(this, x));
        TotalValue = Items.Sum(x => x.Value);
    }
}
于 2013-07-11T01:18:00.763 回答
2

这里有两个主要部分需要考虑。

首先,正如您已经指出的那样,如果您按照更狂热的 RavenDB 粉丝的话来说,它是一些神话般的野兽,它不受其他普遍接受的良好应用程序设计法则的约束,应该被允许随意渗透到您的应用程序中。

当然,这取决于具体情况,但简单地说,如果您要使用 SQL Server 之类的东西以某种方式构建应用程序,那么对 RavenDB 也一样。如果你有一个 DAL 层、ORM、存储库模式或任何带有 SQL Server 后端的东西,那么对 RavenDB 做同样的事情。如果您不介意抽象泄漏,或者项目小到根本不保证抽象您的数据访问,请相应地编码。

RavenDB 的主要区别在于您获得了一些东西,例如工作单元和“免费”的 ORM,但整体解决方案架构不应该有那么不同。

第二,连接其他客户端。为什么控制台应用程序(或任何其他客户端)会以与您的网站不同的方式访问您的 RavenDB 服务器实例?即使您在 ASP.NET 应用程序中运行服务器嵌入模式,您仍然可以使用相同的 RavenDB.Client 代码将其他客户端连接到它。您不需要直接接触 Web 服务 API。

于 2013-07-10T05:48:56.027 回答