2010-06-21 188 views
1

赦免長度在這裏...希望我沒有走極端......適當的位置 - 業務邏輯或數據訪問

我在我的第一個生產MVC工作的過程應用程序,我試圖在這個過程中堅持DDD原則。我遇到了一些與如何處理應用程序的安全需求相關的問題,並認爲我會看到SO社區是否可以提供一些最佳實踐建議。

域信息

要使用一個簡單的解釋,這個應用程序將有AffiliateCompaniesUsersCustomers

  • AffiliateCompanies是層次結構,因此一個子公司可以註冊並與另一個子公司的活動聯繫起來。根源是提供產品/服務的主要公司。
  • Users都屬於一個會員實體。
  • Customers是產品/服務銷往的組織。附屬公司被分配給客戶,使得兩個不相關的分支機構有可能拆分客戶。

安全信息

權限來執行應用程序中的某些行爲會基於一個ACL型排列來確定。每個User對象都具有一個屬性SystemAccessRules,它們確定它們可以執行哪些操作以及它們的權限範圍(它們自己的對象,它們的子公司的對象或它們的整個層次結構的對象)。用戶也可以屬於角色,它們本身具有相同的SystemAccessRules集合。因此,如果用戶登錄並希望查看「他們」客戶的列表,則該列表可以由他們單獨分配給的客戶,分配給他們的分支機構中的任何人的客戶或客戶組成任何人在他們的組織或任何他們的子會員組織被分配到。

數據庫注意事項

DDD不談,在某些點上存儲策略已開始發揮作用。在這個簡單的情況下,該表與上述對象(包括角色表),有幾個支持表對齊支持對象之間的關係:

  • AffiliateCustomers - 該表允許許多一對多通過將每個實體的PK作爲一對FK存儲在關聯公司和客戶之間的關係,這些FK本身就是該表的組合PK。
  • ACL - 此表存儲安全信息,特別是條目主題(用戶或角色),所涉及的操作(例如「CreateCustomer」),權限(允許或拒絕)以及範圍(他們自己的東西,他們的組織或他們的網絡)。

The Question ...最後

我正在使用存儲庫和服務的組合。我試圖將業務邏輯保留在服務中,並保留在存儲庫或數據庫之外,但由於此處的安全設計,對「其」客戶列表的簡單請求可能會非常繁重,特別是隨着數據集的增長。我試圖儘可能地使用Linq,但是這種架構似乎並不適合。在我看來,這裏是我的選擇:

  1. 接受請求的用戶作爲服務方法參數(或通過上下文確定它),並有服務方法填充通過多種查詢到LINQ庫列表。這需要拉取客戶列表,然後遍歷每個客戶發出另一個查詢以拉取ACL數據,然後使用該數據根據權限過濾第一個列表。如果可能的話,層次問題將需要一些奇特的Linq步法(如this)。
    即使可以作出層次問題的工作,好像這個解決方案將不執行得非常好...

  2. 接受請求的用戶作爲一個參數,但它傳遞和所需的權限(例如「查看客戶」)到存儲庫,以便通過存儲過程從數據庫中檢索適當的數據,該存儲過程將使用CTE查詢中的幾個EXISTS子句,這可以說明數據的層次性質以及需要檢查角色和用戶安全。
    這將相當數量的邏輯推送到數據庫,這看起來非常反DDD並且通常很糟糕。

我靠着更傾向於第二種方案,但可能是因爲在我過去的項目即是如何我已經做到了。我甚至不確定我的設計是否在正確的軌道上(過去,權限聲明是使用位標誌完成的,因此使用按位運算符進行數據庫查詢更容易)。

是否有人遇到過類似情況?如果是的話,您是否可以評論您所追求解決方案的性能和可維護性?我想堅持高尚的編程原則,但不要以簡單和常識爲代價。

+0

只是一個評論,而不是一個答案,但要記住KISS和YAGNI的原則。圍繞存儲庫/服務接口設計應用程序代碼,以便始終將內部數據從1更改爲2.然後執行最簡單,最簡單的實現。例如。 2如果這是你習慣的。不要過多地投入設計,因爲你錯過的東西可能會在以後打破它。試着保持足夠的抽象,然後逐步重構。 – queen3 2010-06-21 21:02:04

+0

是的,我正在努力抵制過度設計工程師對現在不是現實的預期需求的衝動。同時我不想讓自己陷入一個角落。我想我必須做一些測試,看看它是如何通過查看列表中每個「AffiliateCompany」對象上的IEnumerable 屬性的內容來評估安全性。在這一天結束的時候,這就是我將數據庫中的數據放入數據庫的問題......我知道數據庫會更快,但我不知道速度有多快。 – 2010-06-21 21:21:40

回答

0

您是否考慮過使用specification pattern將業務規則傳遞給數據訪問層?

該服務構造一個它傳遞給存儲庫的規範樹。存儲庫將規範轉換爲Expression<Func<Customer, bool>>,並將其傳遞到IQueryable<Customer>.Where(...)。當儲存庫實現該集合時,例如通過調用ToList(),將業務規則翻譯成SQL並在數據庫服務器上執行。

我上次檢查時,LINQ to SQL不支持CTE,因此您可能需要使用視圖來扁平化層次結構。

+0

看看這種模式,我喜歡代碼更易於閱讀。現在我使用擴展方法Has(enum)來測試指定的安全枚舉是否是用戶角色的一部分,但這並不是那麼糟糕。我最終以#2的方式發送用戶和角色信息到數據庫,並讓它過濾結果。它確實有效並且表現非常好,但由於跟蹤數據庫更改變得更加困難,因此維護工作有點難度。對錶格的更改意味着對視圖,功能,sprocs等的更改 – 2011-02-11 17:40:32