4

我想弄清楚如何解決這個問題:存儲庫模式,POCO,ORM和中間實體

我有3個表與多對多的關係。

Users *-* Roles *-* Permissions 

我使用ORM從它們獲取數據。

我的業務層必須返回每個權限的用戶的方法,所以我用這個類返回對象:

public class UsersPerPermission 
{ 
    public User[] {get;set;} 
    public Permission {get;set;} 
} 

但此類不映射到存儲庫中的任何表,這是我從生成現有的表格。這個階級應該在哪裏生活?

換句話說:

  • 我應該有一個IRepository.GetUsersPerPermission()?然後該類應該存儲在存儲庫中。

  • 或者我應該有一個IBusinessLayer.GetUsersPerPermission()?然後我必須調用存儲庫中的CRUD方法?

這是有道理的把它的業務層而已,因爲庫應該只是暴露CRUD操作的表...但是,爲了從業務層執行此操作,我將不得不執行幾個獨立的查詢來獲取數據並創建'UserPerPermission'類。另一方面,如果我將其放入存儲庫,則可以使用分組一次性獲取這些信息。

謝謝!

PS:這個中間對象的名稱是什麼? 「轉變」?

+0

關聯類? – 2012-08-31 15:16:58

+0

爲什麼「我的業務層的方法必須允許每個用戶返回用戶」? –

+0

因爲有一些關於用戶和權限管理的屏幕 – vtortola

回答

3

在DDD中,大多數實體和值對象都應該對應於您的ubiquitous language中已識別的域概念。我通常儘量限制多對多關係和人爲關聯對象。埃裏克埃文斯在他的書中描述了一些允許這樣做的技術。當我必須創建一個關聯對象時,它必須有一個關於域的有意義的名字,基本上我從來沒有將它命名爲Class1ToClass2。 在你的情況下,它更人工因爲你的對象:

  • 將冗餘模式,已經存在(間接)的原始模型的關聯。
  • 有一個名稱不反映任何特定的業務概念。

注意,這種類型的對象不會是無用的,如果我們在演示文稿或應用層,它可以派上用場有含究竟是什麼顯示在屏幕(DTO)上的結構。但我在這裏討論域的層,它應該沒有這樣的組合對象。

所以我不會首先創建一個UsersPerPermission類。如果您想要的是用戶列表,並且用戶是聚合根目錄,只需在UserRepository中創建一個GetUsersByPermission()方法。這並不意味着您在應用程序服務中也不能有GetUsersByPermission()方法,前提是它與您的應用程序的用例(一個顯示一個權限的詳細信息和具有該權限的用戶列表的屏幕相匹配)。

+0

問題是,應用程序有一個屏幕,您可以看到按權限分組的用戶。按照你的方法,這是合理的,我必須調用'GetUsersPermissions',並且對於每個'Permission'調用'GetUsersByPermission',對數據庫來說意味着很多查詢。另一方面,有了這個非常好的聚合,我可以在一個查詢中得到所有信息。 – vtortola

+1

你可以擁有多少個權限?如果它們數量衆多,它們是否能夠首先與所有用戶一起顯示在屏幕上?由於(假設的)性能問題來自用戶界面,因此無法在用戶界面中解決該問題,首先只顯示權限,然後顯示關聯的用戶(如果您單擊特定權限)?或者只是前幾​​個權限+用戶和懶加載滾動下面的那些? ... – guillaume31

+1

此外,你可能想看看這裏給出的偉大答案:http://stackoverflow.com/questions/5477506/how-to-implement-ddd-repository-to-handle-a-query-與多個實體和這裏:http://stackoverflow.com/questions/2098112/ddd-how-to-implement-high-performing-repositories-for-searching – guillaume31

0

我同意guillaume31,沒有必要引入一個域對象「UsersPerPermission」來支持一個用例。

有兩種方法可以使用現有域類「用戶」,「角色」和「權限」來實現您的用例。


解決方法一:

假設你有:權限 - >角色 - >用戶

箭頭表示適航。權限具有與角色列表的關聯,角色具有與用戶列表的關聯。

我會添加一個方法GetPermittedUsers() : List<User>到Permission類,這是微不足道的實現。

Th UI邏輯將調用PermissionRepository的GetPermissions(),然後在每個Permission上調用GetPermittedUsers()。

我假設你使用像hibernate(Nhibernate)這樣的ORM框架並正確地定義了多對多關係。如果您定義了來自權限的角色和用戶的預加載,則ORM將生成一個查詢,將權限,角色和用戶表連接在一起,並一次加載所有內容。如果爲角色和用戶定義了延遲加載,則當您調用PermissionRepository時,您將在一個查詢中加載權限列表,然後在另一個查詢中加載所有關聯的角色和用戶。一切從數據庫加載最多三個查詢。這被稱爲1 + n問題,大多數ORM可以正確處理。


解決方法二:

假設你有:用戶 - >角色 - >權限

箭頭表示適航。用戶有一個角色列表。角色具有權限列表。

我會將getUsersByPermissions(List<long> permissionIds) : List<Users>添加到UserRepository,並將getPermissions() : List<Permission>添加到User類。

UserRepository的實現需要在單個查詢中將用戶,角色和權限表一起加入,並一次加載所有內容。再次,大多數ORM將正確處理它。

一旦你有一個用戶列表,你可以創建一個方法來構建一個Map<Permission, List<User>>很容易。


說實話,我很喜歡解決方案之一。我避免寫一個複雜的方法來將用戶列表轉換爲權限和用戶的映射,因此我不需要擔心在哪裏放置此方法。但是,如果您已經在另一個方向上具有導航功能,則可以在用戶,角色和權限類之間創建循環關係。有些人不喜歡循環關係。如果用戶需求,我認爲循環關係甚至可以在某個時候被接受。

0

在我在返回像

IEnumerable<KeyValuePair<PermissionName, IEnumerable<Username>>> 

東西通過使用KeyValuePair <域服務中使用的查詢方法類似的上下文>我避免用人工概念污染域模型(如UsersPerPermition) 。而且這樣的結構是不變的。 我沒有在存儲庫上使用查詢方法,因爲在我的上下文中,沒有實體與另一個實體耦合。所以這對任何倉庫都不是問題。

但是,這個解決方案對於您的GUI有用,當且僅當您正確建模實體的標識符(在您的示例中,權限和用戶都是實體)。 事實上,如果它們屬於用戶理解的無處不在的語言的shared identifiers,它們就足夠了,無需進一步描述。

否則,你只是爲你的GUI建立一個有用的DTO。它不屬於域,因此您應該使用最簡單的工作方式(ADO.NET查詢更簡單些?)。 事實上,在我自己的場景中,GUI和域都使用了這樣的服務(該GUI顯示了詳細的預覽)。

一般來說,領域模型必須反映領域專家的語言,捕捉與有界上下文相關的知識。其他一切必須在域之外(但大部分時間可以用域的價值對象來表示)。