2017-06-22 3 views
1

In unserem Web.API-Projekt verwenden wir Entity Framework 6. Wir haben eine DataModel-Klasse, die den DatabaseContext enthält. Das DataModel ist ein [ThreadStatic] Singleton.EF-Kontext in der Modellklasse

So:

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(); 
    } 
} 

nun in einem unserer (Teil-) Modellklassen, verwenden wir den Kontext wie folgt aus:

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

Wir in einer anderen Tabelle die entsprechenden Benutzer in der Datenbank zu suchen . Das funktioniert, aber meiner Meinung nach ist das keine schöne Lösung. Vor allem, wenn wir unser Projekt auf .NET Core migrieren und Dependency Injection für den Datenbankkontext verwenden wollen.

Meine Frage ist, gibt es ein Muster, das das Problem eleganter löst? Die Abhängigkeitseinspeisung funktioniert hier nicht, da Entity Framework die Modellobjekte generiert. Oder wäre es besser, wenn wir diesen Code von der Teilklasse zu z. eine Util-Klasse? Aber wie können wir dort den Kontext einspeisen?

+1

Sowohl ein Singleton-Kontext als auch die Verwendung von Kontexten innerhalb von Entitätsklassen sind Antimuster. Also versuchen Sie zuerst, diese Muster loszuwerden, ohne sich um DI zu kümmern. Sie werden sehen, dass es danach viel einfacher ist, den Code in DI zu konvertieren. * Wie * das zu tun, hängt zu sehr vom Rest deiner Architektur ab, um etwas Sinnvolles darüber zu sagen. –

+0

In welcher Schicht befindet sich dieses Datenmodell? Ist es das Modell, das von der API zurückgegeben wird, oder ein Versuch einer Datenbankabstraktionsschicht? Generell würde ich vorschlagen, ein Repository-Muster zu verwenden, aber das passt nicht zu allen Problemen. Wenn sich Modelle über Datenbankaufrufe selbst bevölkern (das "aktive Datensatzmuster"), verursacht das im Allgemeinen mehr Probleme als es löst. – CodeCaster

+0

Die Verwendung von richtigen Fremdschlüsseln würde das Problem lösen. Der Job wird durch den Benutzer CreatedBy * auf UserId * und nicht durch den Benutzernamen verknüpft (es sei denn, Benutzername ist der PK in Ihrer Benutzertabelle. In diesem Fall sollten Sie dies neu überdenken). Ordnen Sie diese Beziehung in EF zu, und Sie können dann zu dem CreatedByUser navigieren, indem Sie entweder "Lazy Loading" verwenden, wenn die Entität angehängt ist, ODER sie sofort mithilfe einer Include-Klausel in der Abfrage abrufen. Ihre aktuelle Lösung ist nicht threadsicher, vor allem wenn man bedenkt, dass Sie eine asp.net App haben, die mehrere Threads hat (1x gleichzeitige Anfrage bei minimum). – Igor

Antwort

0

Sie möchten es im Allgemeinen vermeiden, dass Ihre Modelle auf ihren Erstellungs- und Nutzungskontext achten müssen, da dieses Wissen von oben nach unten und nicht von unten nach oben erfolgen sollte. Unter anderem werden Sie auf Design-Probleme stoßen, wie Sie sie gerade erleben. Sie können versuchen, sich auf Anwendungsebene mit Erweiterungsmethoden, einer Inversion des Control-Frameworks, Utility-Methoden, Pocos usw. zu orientieren, aber am Ende des Tages versuchen Sie, ein Problem zu lösen, das nur aufgrund Ihres Basiswerts existiert Das Datenbankschema ist für die beabsichtigte Verwendung nicht ausreichend ausgelegt.

Zum Beispiel hat Ihre Job Tabelle einen Verweis auf den Benutzernamen des Benutzers, der es erstellt hat. Warum? Es kann sein, dass sich Benutzernamen ändern können und jedes Mal, wenn Sie zusätzliche kritische Eigenschaften dieses Benutzers wünschen, müssen Sie eine sekundäre Suche durchführen (wie Sie es in Ihrer partiellen Klasse tun). Wenn Sie stattdessen die Tabelle Job einen Fremdschlüssel für die Tabelle User verwalten, können Sie einfach eine Navigationseigenschaft auf der C# -Seite verwenden, um das vollständige Benutzerobjekt abzurufen, solange die entsprechenden verwandten Entitäten in der Abfrage enthalten sind. Sie würden nicht einmal die partielle Klasse benötigen und Ihr Datenbankschema würde als zusätzlicher Bonus wartungsfreundlicher werden.

Manchmal ist es am besten, den Datenbankentwurf zu vereinfachen, um den Code zu vereinfachen.

Verwandte Themen