使用RavenDB时,我应该在哪里放置业务逻辑

ste*_*776 3 .net c# nosql ravendb servicestack

我打算使用RavenDB作为我的数据存储来构建单页面应用程序(SPA).

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

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

在RavenDB之上使用任何类型的存储库或其他抽象并且直接在控制器内部(在MVC应用程序中)使用RavenDB API时,大多数当前的观点似乎都不屑一顾

我假设我在使用Raven和ServiceStack时应该遵循同样的智慧,并直接在我的服务实现中对IDocumentSession进行调用.

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

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

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

编辑

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

Phi*_*rdt 7

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

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

  2. 服务层.使用ServiceStack的Web服务,其中干净/相当扁平的DTO与Domain对象完全分离.Web服务负责管理事务和所有RavenDB交互.大多数'Command-ish'服务操作包括:a)加载由请求标识的域对象(文档),b)调用业务逻辑,c)将结果转换为响应DTO.我们已经扩充了ServiceStack,以便许多Command-ish操作使用自动处理程序来执行上述所有操作,而无需任何代码.'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);
    }
}
Run Code Online (Sandbox Code Playgroud)