2013-07-10 100 views
3

我打算使用RavenDB作爲我的數據存儲來構建單頁應用程序(SPA)。我應該在使用RavenDB時應該放置什麼業務邏輯

我想從SPA片的ASP.NET Hot Towel模板開始。

我將刪除EntityFramework/WebApi/Breeze組件並將其替換爲RavenDB的存儲和ServiceStack以構建後端API。

目前大多數的意見似乎在使用任何類型的存儲庫或附加的抽象對RavenDB的頂部皺眉,並呼籲直接使用RavenDB API控制器內(在MVC應用程序)

我假設我應該遵循將Raven與ServiceStack結合使用並直接在我的服務實現中對IDocumentSession進行調用時也是如此。

我的擔憂在於,看起來我的服務實現會變得相當臃腫,因爲遵循此路徑。我似乎還經常需要多次編寫相同的代碼,例如,如果我需要更新多個不同Web服務端點中的用戶文檔。

我似乎也需要從我的應用程序的其他(未來)部分訪問Raven。例如,我可能需要添加一個控制檯應用程序來處理未來隊列中的作業,並且這部分應用程序可能需要訪問Raven中的數據......但是從一開始,我唯一通往Raven的路徑將通過Web服務API。我只是打算從這個理論控制檯應用程序調用web api?如果它們可能運行在相同的硬件上,看起來效率低下。

任何人都可以提供任何建議,如何在我的web服務和其他地方有效利用Raven,同時仍然遵循使用此文檔商店的最佳做法?創建一箇中間業務邏輯層直接處理針對raven的調用似乎很實際...允許我的web服務調用此層中的方法。這有意義嗎?

編輯

誰能提供最近的任何類似架構的樣本?

回答

7

FWIW,我們目前正在使用ServiceStack和RavenDB開發應用程序。我們正在使用DDD方法,並將我們的業務邏輯放在一個豐富的域層中。該架構是:

  1. Web App。承載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。修改域對象狀態的唯一方法是調用方法。域對象公開了旨在被服務層使用的公共方法,或公開的方法,以便在域層中使用。領域層引用消息組件,主要是爲了允許我們的領域對象上的方法接受複雜的請求對象,並避免使用長參數列表的痛苦的方法。

  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); 
    } 
} 
+0

感謝您的詳細解答!我研究的越多,我越傾向於你所描述的建築。你能提供一個典型的域對象用什麼方法來設置屬性的例子嗎? – stephen776

2

這裏有兩個主要部分需要考慮。首先,正如你已經注意到的那樣,如果你用更狂熱的RavenDB的粉絲的話來說,這是一個神話般的野獸,它是免除了其他普遍接受的良好應用程序設計的法則,應該允許它貫穿你的整個隨意應用。

這取決於當然的情況,但簡單來說,如果你想用某種類似SQL Server的結構來構建你的應用程序,那麼就和RavenDB一樣。如果你有一個DAL層,ORM,存儲庫模式或其他任何與SQL Server後端,對RavenDB也一樣。如果您不介意漏洞抽象,或者該項目足夠小以至於不能保證抽象您的數據訪問,則相應編碼。

與RavenDB的主要區別在於,您可以獲得諸如「工作單元」和「免費」的ORM等一些內容,但整體解決方案體系結構應該與此不同。

二,連接其他客戶端。爲什麼控制檯應用程序或任何其他客戶端會爲您的網站訪問您的RavenDB服務器實例?即使您在ASP中運行服務器嵌入模式。NET應用程序,您仍然可以使用相同的RavenDB.Client代碼連接其他客戶端。您不需要直接觸摸Web服務API。

+0

是的,從另一個客戶端調用RavenDB應該沒有任何不同於Web服務。我的錯誤,這是一個不好的例子。 – stephen776

相關問題