Ich verwende derzeit eine DbContext
ähnliche:
namespace Models
{
public class ContextDB: DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<UserRole> UserRoles { get; set; }
public ContextDB()
{
}
}
}
Ich verwende dann die folgende Zeile oben auf ALLEN meinen Controllern, die Zugriff auf die Datenbank benötigen. Ich benutze es auch in meiner UserRepository-Klasse, die alle Methoden enthält, die sich auf den Benutzer beziehen (z. B. den aktiven Benutzer abrufen, überprüfen, welche Rollen er hat usw.):
ContextDB _db = new ContextDB();
Denken Sie darüber nach. Es gibt Fälle, in denen ein Besucher mehrere DbContexts aktiv haben kann. Wenn er einen Controller besucht, der das UserRepository verwendet, ist dies möglicherweise nicht die beste Idee, und ich habe ein paar Fragen dazu
- Wann sollte ich einen neuen DbContext erstellen / sollte ich einen globalen Kontext haben, den ich weitergebe?
- Kann ich einen globalen Kontext haben, den ich an allen Orten wiederverwenden kann?
- Verursacht dies einen Leistungseinbruch?
- Wie machen das alle anderen?
DbContext
pro Anforderung eine erstellt wird. Ich würde auch eine Serviceschicht erstellen. Überprüfen Sie diese SO Frage & AntwortAntworten:
Ich verwende einen Basis-Controller, der eine
DataBase
Eigenschaft verfügbar macht , auf die abgeleitete Controller zugreifen können.public abstract class BaseController : Controller { public BaseController() { Database = new DatabaseContext(); } protected DatabaseContext Database { get; set; } protected override void Dispose(bool disposing) { Database.Dispose(); base.Dispose(disposing); } }
Alle Controller in meiner Anwendung stammen von folgenden Anwendungen
BaseController
und werden wie folgt verwendet:public class UserController : BaseController { [HttpGet] public ActionResult Index() { return View(Database.Users.OrderBy(p => p.Name).ToList()); } }
Um Ihre Fragen zu beantworten:
Der Kontext sollte pro Anfrage erstellt werden. Erstellen Sie den Kontext, tun Sie, was Sie damit tun müssen, und entfernen Sie ihn dann. Mit der von mir verwendeten Basisklassenlösung müssen Sie sich nur um die Verwendung des Kontexts kümmern.
Versuchen Sie nicht, einen globalen Kontext zu haben (so funktionieren Webanwendungen nicht).
Nein, wenn Sie einen Kontext beibehalten, werden alle Aktualisierungen, Ergänzungen, Löschungen usw. nachverfolgt. Dies verlangsamt Ihre Anwendung und kann sogar dazu führen, dass in Ihrer Anwendung einige ziemlich subtile Fehler auftreten.
Sie sollten sich wahrscheinlich dafür entscheiden, entweder Ihr Repository oder Ihren Kontext für Ihren Controller verfügbar zu machen, aber nicht für beide. Wenn zwei Kontexte über dieselbe Methode aufgerufen werden, führt dies zu Fehlern, wenn beide unterschiedliche Vorstellungen über den aktuellen Status der Anwendung haben.
Persönlich ziehe ich es vor,
DbContext
direkt zu belichten, da die meisten Repository-Beispiele, die ich gesehen habe,DbContext
sowieso nur als dünne Wrapper enden .Das erste Mal, wenn ein
DbContext
erstellt wird, ist ziemlich teuer, aber sobald dies geschehen ist, werden viele Informationen zwischengespeichert, so dass nachfolgende Instanziierungen viel schneller sind. Es ist wahrscheinlicher, dass Leistungsprobleme auftreten, wenn ein Kontext beibehalten wird, als wenn Sie jedes Mal, wenn Sie Zugriff auf Ihre Datenbank benötigen, eines instanziieren.Es hängt davon ab, ob.
Einige Benutzer bevorzugen die Verwendung eines Abhängigkeitsinjektionsframeworks, um eine konkrete Instanz ihres Kontexts beim Erstellen an ihren Controller zu übergeben. Beide Optionen sind in Ordnung. Meins ist besser für eine kleine Anwendung geeignet, bei der Sie wissen, dass sich die verwendete Datenbank nicht ändern wird.
Einige argumentieren möglicherweise, dass Sie dies nicht wissen können, und deshalb ist die Methode der Abhängigkeitsinjektion besser, da sie Ihre Anwendung widerstandsfähiger gegenüber Änderungen macht. Ich bin der Meinung, dass sich dies wahrscheinlich nicht ändern wird (SQL Server und Entity Framework sind kaum unklar) und dass meine Zeit am besten damit verbracht wird, den für meine Anwendung spezifischen Code zu schreiben.
quelle
Ich versuche aus eigener Erfahrung zu antworten.
1. Wann sollte ich einen neuen DbContext erstellen / sollte ich einen globalen Kontext haben, den ich weitergebe?
Der Kontext sollte durch die Abhängigkeitsinjektion injiziert und nicht von Ihnen selbst instanziiert werden. Best-Practice besteht darin, es durch die Abhängigkeitsinjektion als Scoped-Service erstellen zu lassen. (Siehe meine Antwort auf Frage 4)
Bitte erwägen Sie auch die Verwendung einer geeigneten mehrschichtigen Anwendungsstruktur wie Controller> BusinessLogic> Repository. In diesem Fall empfängt Ihr Controller nicht den Datenbankkontext, sondern das Repository. Das Einfügen / Instanziieren eines Datenbankkontexts in einen Controller zeigt mir, dass Ihre Anwendungsarchitektur viele Verantwortlichkeiten an einem Ort vereint, was ich unter keinen Umständen empfehlen kann.
2. Kann ich einen globalen Kontext haben, den ich an allen Orten wiederverwenden kann?
Ja, Sie können haben, aber die Frage sollte sein " Sollte ich haben ..." -> NEIN. Der Kontext soll pro Anfrage verwendet werden, um Ihr Repository zu ändern, und dann ist es wieder weg.
3. Verursacht dies einen Leistungseinbruch?
Ja, weil der DBContext einfach nicht dafür gemacht ist, global zu sein. Es speichert alle Daten, die eingegeben oder abgefragt wurden, bis sie zerstört werden. Das bedeutet, dass ein globaler Kontext immer größer wird, die Vorgänge darauf immer langsamer werden, bis Sie Ausnahmen aufgrund von Speichermangel bekommen oder an Altersschwäche sterben, weil sich alles zu einem Crawl verlangsamt hat.
Sie erhalten auch Ausnahmen und viele Fehler, wenn mehrere Threads gleichzeitig auf denselben Kontext zugreifen.
4. Wie machen das alle anderen?
DBContext, der durch Abhängigkeitsinjektion von einer Fabrik injiziert wird; Umfang:
services.AddDbContext<UserDbContext>(o => o.UseSqlServer(this.settings.DatabaseOptions.UserDBConnectionString));
Ich hoffe meine Antworten waren hilfreich.
quelle
Im Moment versuche ich diesen Ansatz, der es vermeidet, den Kontext zu instanziieren, wenn Sie Aktionen aufrufen, die ihn nicht verwenden.
public abstract class BaseController : Controller { public BaseController() { } private DatabaseContext _database; protected DatabaseContext Database { get { if (_database == null) _database = new DatabaseContext(); return _database; } } protected override void Dispose(bool disposing) { if (_database != null) _database.Dispose(); base.Dispose(disposing); } }
quelle
GC.GetTotalMemory()
zurückgegeben wurde (nicht perfekt, aber es ist das, was ich gefunden habe), und der Unterschied war nie größer als 8 KB.Dies ist offensichtlich eine ältere Frage, aber wenn Sie DI verwenden, können Sie so etwas tun und alle Ihre Objekte für die Lebensdauer der Anforderung erfassen
public class UnitOfWorkAttribute : ActionFilterAttribute { public override void OnActionExecuting(HttpActionContext actionContext) { var context = IoC.CurrentNestedContainer.GetInstance<DatabaseContext>(); context.BeginTransaction(); } public override void OnActionExecuted(HttpActionExecutedContext actionContext) { var context = IoC.CurrentNestedContainer.GetInstance<DatabaseContext>(); context.CloseTransaction(actionContext.Exception); } }
quelle
Sie sollten den Kontext sofort nach jedem Save () - Vorgang entsorgen. Andernfalls dauert jedes weitere Speichern länger. Ich hatte ein Projekt, das komplexe Datenbankentitäten in einem Zyklus erstellt und gespeichert hat. Zu meiner Überraschung wurde der Vorgang dreimal schneller, nachdem ich "using (var ctx = new MyContext ()) {...}" innerhalb des Zyklus verschoben hatte.
quelle