2010-04-14 10 views
7

was ist die bevorzugte Praxis, wenn linq2sql mit (in asp.net MVC-Anwendungen):linq2sql: Singleton oder verwenden, Best Practices

partial class db 
{ 
    static db _db = new db(global::data.Properties.Settings.Default.nanocrmConnectionString, new AttributeMappingSource()); 

    public static db GetInstance() 
    { 
     return _db; 
    } 
} 

oder abzurufen neue Instanz, wenn: "Singletons" für DataContext wie erstellen es benötigt innerhalb using:

using (db _db = new db()) 
{ 
    ... 
} 

die Verwendung von using bringt einige Einschränkungen in den Code. also bevorzuge ich Singleton. ist es eine seltsame Übung?

UPD:
Erklärung, warum ich Singletons bin mit:

public class UserGroupRepository 
{ 
    public static IQueryable<Group> RolesFor(string username) 
    { 
     User user = UserRepository.WithUsername(username); 

     return from g in db.GetInstance().Groups 
       join ug in db.GetInstance().UsersGroups on g.Id equals ug.GroupId 
       where ug.UserId == user.Id 
       select g; 
    } 
} 

Ich habe diese Methode. aufgrund der Rückgabe IQQueryable - ich kann weiter komponieren Abfrage ohne es auszuführen, so hier nur faule Ergebnis zurück.
wenn ich den gleichen Code mit using umschreibe - ich kann nicht IQueryable zurückgeben (weil db wird entsorgt und IQueryable wird auch verloren), und ich würde es in Liste ändern. und jetzt wird diese Methode "riesige" Liste zurückgeben, von der ich Daten über die vorherige Funktion filtern werde.

ich hoffe ich beschreibe genug ausführlich.

+0

aus Neugier, welche Einschränkungen macht die Verwendung von "verwenden"? Vielleicht gibt es einen schönen Weg, sie zu umgehen ... – LorenVS

+0

@LorenVS: Ich wette, dass "Einschränkungen" sind, weil ich ein Neuling bin, also glaube ich, dass es auch eine elegante Lösung mit 'using' gibt ;-) – zerkms

+0

Hinzugefügt zu mein Beitrag zu Ihrem Update – LorenVS

Antwort

5

Linq-zu-Sql-Datenkontexte sind NICHT Thread-sicher und sollten nur im Zusammenhang mit einem einzelnen Thread verwendet werden. Die Verwendung des Singleton-Patterns steht nicht nur im Gegensatz zu den Standardverfahren von linq2sql, sondern führt zu ernsthaften Problemen, wenn Ihre Anwendung ernsthaft belastet wird.

EDIT:

Als Antwort auf Ihre Grenzen im Hinblick auf die Verwendung von Block, versuchen Sie RolesFor Methode als Erweiterung Methode implementieren:

public static IQueryable<Group> GetUserRoles(this Database db, string username) 
{ 
     return from g in db.GetInstance().Groups 
       join ug in db.GetInstance().UsersGroups on g.Id equals ug.GroupId 
       where ug.UserId == user.Id 
       select g; 
} 

Dies würde ermöglichen es Ihnen, Ihre Methode innerhalb anrufen ein mit Block von überall:

using(Database db = createContext()) 
{ 
    IQueryable<Group> queryable = db.GetUserRoles("MyUsername"); 
    // from here on you can query the queryable object 
    var groups = (from g in queryable 
        where g.Name == "MyRole" 
        select g).ToList(); 
} 

EDIT 2

In Erwiderung auf Ihren Kommentar zum Öffnen einer anderen Verbindung zum SQL-Server für jede Instanz des Datenkontextes. Durch das Erstellen eines Datenkontextes wird keine Verbindung zum SQL-Server hergestellt, sondern jede tatsächliche Operation. Unabhängig davon, ob Sie 1 oder 4 Datenkontexte erstellen, werden 4 SQL-Verbindungen geöffnet, wenn Sie 4 Operationen für die Datenbank ausführen. Beachten Sie jedoch, dass .NET einen SQL Server-Verbindungspool verwendet, sodass für jede Operation nicht die Erstellung einer vollständig neuen SqlConnection erforderlich ist, sondern nur das Abrufen einer vorhandenen Verbindung aus dem Verbindungspool und das erneute Öffnen der Verbindung

+0

@LorenVS: ich füge ** UPD ** zur ursprünglichen Frage hinzu mit erklären, warum ich gefragt habe die Frage. – zerkms

+0

das wird funktionieren, aber das verschwendet "db" -Klasse und ist konzeptionell falsch. – zerkms

+1

@zerkms, bitte klären Sie, was Sie meinen, auf welche Weise ist es konzeptionell falsch und was meinst du mit verschwenden db Klasse – LorenVS

0

Wahrscheinlich möchten Sie die Lebensdauer Ihres Kontextes verwalten, damit er auf eine einzelne Webanfrage beschränkt ist und nur einen Kontext für die Lebensdauer dieses Webanforderungszyklus hat.

Google Suche nach 'web scoped objectcontext' oder 'objectcontext lifetime' (oder Datenkontext für l2s).

z.B.http://dotnetslackers.com/articles/ado_net/Managing-Entity-Framework-ObjectContext-lifespan-and-scope-in-n-layered-ASP-NET-applications.aspx

In MVC2 können Sie den Kontextverwaltungscode in Ihre Basiscontroller-Klasse einfügen.

+0

yep, dies wird funktioniert auch, aber sieht aus wie 'diiiiiiirty hack' – zerkms

+0

Nein, das ist gängige Praxis. Siehe auch http://stackoverflow.com/questions/196253/linq-to-sql-where-does-your-datacontext-live –

+0

so, Wenn ich einen Datenkontext pro Anfrage erzeuge (mit Speicherung im Wörterbuch wie in "Eine gemeinsame ObjectContext-Instanz pro HTTP-Anfrage" beschrieben) - wie sie später entsorgt werden, nachdem alle HttpContext.Current.Items (oder sogar HttpContext .Current) wird Müll automatisch gesammelt? – zerkms

2

Linq to SQL möchte, dass Sie einen Kontext pro Vorgang erstellen. Tatsächlich können die Datenladeoptionen nur für die Ausführung der ersten Abfrage festgelegt werden. Wenn Sie also Ladehinweise ausführen möchten, müssen Sie dies tun. Wenn Sie jedoch eine 3-Tier-Architektur haben, werden Sie auf das Problem stoßen, dass Objekte aus einem Datenkontext nicht wirklich mit Objekten aus einem anderen Kontext arbeiten können.

Um arbeiten ist das ein echter Schmerz, so haben wir nur einen Kontext pro Anfrage für Web-Stuff und einen Thread lokalen Ansatz für Windows Services und dergleichen.

+0

yep, wie der oben erwähnte Hightechrider, http-request-context wird das "Problem" lösen, aber für mich (und ich wette für dich) sieht es wie dreckiger Hack aus, nicht wahr? – zerkms

+0

Ich finde immer noch den Wettbewerb pro Anfrage Ansatz leicht böse, vor allem angesichts der Tendenz von Web - Entwicklern, Daten in einer asynchronen Angelegenheit abzurufen ... Das ist nicht die Norm für Ihre Websites, aber wenn jemand beschließt, einen asynchronen Abruf in der hinzufügen Zukünftig warten Sie auf einen Multithread-Fehler ... Ich würde sagen, dass Sie in dieser Situation am besten die Linq2Sql-Objekte in Ihre eigenen Geschäftsobjekte übersetzen würden ... – LorenVS