2017-06-22 66 views
1

在我們的Web.API項目中,我們使用實體框架6.我們有一個DataModel類,它包含DatabaseContext。 DataModel是一個[ThreadStatic] Singleton。模型類中的EF上下文

像這樣:

public class DataModel 
{ 
    [ThreadStatic] private static DataModel _instance; 
    public static DataModel Instance => _instance ?? (_instance = new DataModel()); 

    public DatabaseContext Context { get; private set; } 

    private DataModel() 
    { 
     Context = NewContext(); 
    } 
} 

現在,在我們的(部分)模型類之一,我們使用的情況下是這樣的:

public partial class Job 
{ 
    public User CreatedByUser 
    { 
     get { return DataModel.Instance.Context.Users.FirstOrDefault(d => d.Username == CreatedBy); } 
    } 
} 

我們在另一個數據庫中的表對應的用戶搜索。這是有效的,但在我看來,這不是一個美麗的解決方案。特別是如果我們計劃將我們的項目遷移到.NET Core並對數據庫上下文使用依賴注入。

我的問題是,有沒有一種模式,它解決了更優雅的問題?依賴注入在這裏不起作用,因爲實體框架生成模型對象。或者,如果我們將這些代碼從部分類移動到例如一個util類?但是我們怎麼能在那裏注入上下文呢?

+1

實體類中的單例上下文和上下文都是反模式。所以首先嚐試擺脫這些模式,而不用擔心DI。之後你會看到,將代碼轉換爲DI會更容易。 *如何做到這一點,很大程度上取決於你的架構的其他部分,以便對其進行任何明智的說明。 –

+0

這個datamodel駐留在什麼層?它是從API返回的模型還是嘗試在數據庫抽象層?通常我會建議使用存儲庫模式,但這並不適合所有問題。讓模型通過數據庫調用(「活動記錄模式」)填充自己通常會導致比解決問題更多的問題。 – CodeCaster

+0

使用正確的外鍵可以解決問題。作業是通過UserId *上的CreatedBy用戶*關聯的,而不是用戶名(除非用戶名是用戶表中的PK,在這種情況下,您應該重新考慮這一點)。在EF中映射該關係,然後如果實體已連接,則可以使用延遲加載導航到「CreatedByUser」,或者在查詢中使用「包含」子句立即檢索它。您當前的解決方案不是線程安全的,特別是考慮到您有一個具有多個線程的asp.net應用程序(至少1x同時請求)。 – Igor

回答

0

您通常希望避免要求您的模型意識到其創建和使用環境,因爲該知識應該是自上而下,而不是自下而上。除其他原因外,您會遇到像您現在遇到的設計問題。您可以嘗試在應用程序級別上使用擴展方法,控制框架反轉,實用方法,pocos等設計解決方案,但是在一天結束時,您試圖解決僅存在的問題,因爲您的基礎數據庫模式沒有適合您的預期用法。

例如,您的Job表中引用了創建它的用戶的用戶名。爲什麼?用戶名可能會改變,並且任何時候您想要該用戶的額外關鍵屬性都需要執行輔助查找(就像您在部分班級中所做的那樣)。如果您將Job表保留爲User表的外鍵,那麼只要查詢中包含適當的相關實體,就可以在C#端使用導航屬性來獲取完整的用戶對象。你甚至不需要部分類,你的數據庫模式將變得更加可維護,作爲額外的獎勵。

有時最好簡化數據庫設計以簡化代碼。

相關問題