2013-11-26 45 views
0

作爲一個簡單的例子,我有用戶,產品和客戶。用戶可以訪問某些產品和某些客戶。如何保持客戶數據隔離

我正在使用edmx文件將我的SQL Server映射到我的代碼並使用linq獲取數據。一個典型的查詢可能是這個樣子:

from prod in ctx.Products 
join userProduct in ctx.UserProduct 
on prod.Id equals userProduct.ProductId 

join user in ctx.UserProfile 
on userProduct.UserId equals user.Id 

where user.UserName == username // <-- username is a method parameter 
select new Product 
{ 
    Id = prod.Id, 
    DisplayText = prod.UserFriendlyText 
} 

每次我需要從我必須加入對訪問權限表的數據庫中的數據來排除數據的用戶沒有訪問。這意味着如果有人(最終會發生)忘記加入訪問表,用戶將看到太多。有沒有辦法來INCLUDE數據,所以如果我忘記訪問表什麼都沒有顯示?

我也一直在考慮將不同的客戶分成不同的數據庫,因爲他們的數據永遠不會彼此相關,如果我在客戶之間泄漏數據,這將是一個小小的災難。來自同一客戶的用戶之間泄漏的產品很差,但並不重要。

如果它很重要我在C#MVC4 CQRS體系結構中最終讀寫一致性。

我檢查堆棧溢出類似的問題,但所有我能找到的是這個沒有答案之一:

回答

1

如何使用Repository pattern,並迫使你開發的用它來打電話給數據庫?這將促進代碼重用並提高應用程序的可維護性。

因爲將從存儲庫中調用一個方法,您可以控制與數據庫交互的代碼並強制一致性,這樣可以確保始終使用訪問表並按您的意願使用。

+0

我想一個簡單的存儲庫模式,如方法,接受用戶名作爲參數,並且只返回在'IQueryable'中有權訪問的產品可以工作,但它仍然像我一樣錯誤地可以查詢產品而不加入訪問權限表。 –

+1

然後讓你的開發者不能直接查詢產品。例如,僅爲您的模塊和數據庫API提供Repository接口(然後在運行時使用依賴注入來提供實際的Repository服務)。 –

0

我在我的數據庫中有類似的問題。我的實體中有90%是「依賴於組織」的。我的方法使用類似這樣的方法的通用基礎知識庫:

public virtual T Find(int id) 
    { 
     T e = Context.Set<T>().Find(id); 

     var od = e as OrganisationDependent; 
     if (od != null && od.OrganisationID != CurrentOrganisationID) 
      return null; 

     if (e == null) 
      return null; 

     return e; 
    } 

「全部」方法是一個特殊問題。通過How to conditionally filter IQueryable

private static readonly PropertyInfo _OrganisationIDProperty = ReflectionAPI.GetProperty<OrganisationDependent, int>(o => o.OrganisationID); 

    private static Expression<Func<TOrg, bool>> FilterByOrganization<TOrg>(int organizationId) 
    { 
     //The FilterByOrganisation method uses the LINQ Expressions API to generate an expression that will filter on organisation id 
     //This avoids having to cast the set using .AsEnumerable().Cast<OrganisationDependent>().Where(x => x.OrganisationID == CurrentOrganisationID).AsQueryable().Cast<T>(); 
     //https://stackoverflow.com/questions/20052827/how-to-conditionally-filter-iqueryable-by-type-using-generic-repository-pattern 
     var item = Expression.Parameter(typeof(TOrg), "item"); 
     var propertyValue = Expression.Property(item, _OrganisationIDProperty); 
     var body = Expression.Equal(propertyValue, Expression.Constant(organizationId)); 
     return Expression.Lambda<Func<TOrg, bool>>(body, item); 
    } 

    public virtual IQueryable<T> All 
    { 
     get 
     { 
      if (typeof(T).IsSubclassOf(typeof(OrganisationDependent))) 
       return Context.Set<T>().Where(FilterByOrganization<T>(CurrentOrganisationID)); 

      return Context.Set<T>(); 
     } 
    } 

解決。這將關閉大部分用戶可以訪問別人的數據的地方。但它不會過濾導航屬性。所以我必須將代碼添加到非組織依賴實體上的所有導航屬性才能做到這一點。

我不想將我的數據分成不同的數據庫,但有一天我會發現創建按不同模式組織過濾的視圖是否可行 - 與我的表具有相同的名稱和結構,然後切換模式根據用戶.....哦,我想自動創建它們爲每個新的組織和autmatically利用二維碼的第一太遷移它們....

而且你可以投票Allow filtering for Include extension method這裏

0

如果您您可以使用CQRS風格的體系結構,您可以考慮讓每個用戶擁有一個或多個包含他們有權訪問的產品/客戶的視圖模型。

如果你看到自己不得不在CQRS的查詢方面實現邏輯,這強烈地表明你做錯了什麼。

+0

謝謝Niklas我也有這樣的感覺,在查詢方面的邏輯是錯誤的。你能否詳細說明你將如何做這樣的每個用戶拆分?例如,在處理事件或將事件交給相關訂戶之前會發生這種情況嗎? –

+0

查詢端的實際實現當然會受到存儲引擎的影響,如果是關係,基於文檔等等。 –

+0

如果不知道在什麼情況下使用視圖模型,您真的很難給出一個您需要的視圖模型的例子,但這裏的主要問題是不應該可以查詢它並接收顯示用戶信息但不訪問的結果。如果您使用的是documentDb,則可以將userId作爲鍵幷包含他們有權訪問的產品/ ID列表。 ProductsPerCustomerViewModel或類似產品。然後,該事件需要包含有關viewmodelupdater應該如何知道訪問權限的信息,或者在創建事件之前讓您的域執行該邏輯 –