2009-02-14 21 views
15

Was ist die beste Vorgehensweise beim Einrichten meines DataContext für den einfachen Zugriff in meinen erweiterten LinqToSql-Klassen?LinqToSql deklarieren und instanziieren DataContext Best Practice?

Zum Beispiel, ich habe eine „User“ Einheit in meiner dbml und ich mag wie so diese Klasse Methoden hinzufügen:

Partial Public Class User 

    Public Function GetUser(ByVal UserID as Integer) as User 
     'Do Work 
    End Function 

End Class 

Um meine Datacontext zugreifen Ich würde es im Innern erklären die Methode wie folgt:

Partial Public Class User 

    Public Function GetUser(ByVal UserID as Integer) as User 
     Dim dc as New MyDataContext() 
     Return (From u in dc.Users Where u.ID = UserID).Single() 
    End Function 

End Class 

Ich möchte das nicht für jede einzelne Methode tun müssen. Normalerweise (wenn ich nicht die LinqToSql dbml Klassen erstreckten, wurden) konnte ich dies nur tun:

Partial Public Class User 
    Private dc as MyDataContext 

    Public Sub New() 
     dc = new MyDataContext() 
    End Sub 

    Public Function GetUser(ByVal UserID as Integer) as User 
     Return (From u in dc.Users Where u.ID = UserID).Single() 
    End Function 

    Public Function GetAllUsers() as IEnumerable(Of User) 
     Return From u in dc.Users 
    End Function 

    'etc... 

End Class 

Dies würde erlauben Sie mir für jede Methode der Datacontext zugreifen, ohne sie jedes Mal neu anmelden zu müssen. Das können Sie natürlich nicht machen, da die dbml bereits einen Konstruktor hat. Und das Hinzufügen von Code in die dbml wird immer überschrieben, wenn sich jemals etwas ändert.

Hat jemand gute Ideen, wie Sie mir hier überschüssigen Code sparen können?

TIA!

Antwort

13

Stellen Sie zuerst sicher, dass Sie Ihren DataContext entsorgt haben, wenn Sie fertig sind! Er kann ein schwerer kleiner Bastard sein (bearbeiten nicht schwer zu instanziieren, aber schwer, um herumzuhalten, wenn Sie es verwenden, ohne zu entsorgen); Sie möchten nicht, dass alte DataContexte im Speicher hängen bleiben.

Zweitens, der DataContext soll eine einzelne logische Transaktion darstellen. Z.B. Sie sollten jedes Mal, wenn Sie eine neue Transaktion starten möchten, eine neue erstellen und sie loswerden, wenn die Transaktion abgeschlossen ist. Also für Ihre Zwecke, das ist wahrscheinlich der Anwendungsbereich der GetUser Methode. Wenn Sie eine Reihe von DB-Anrufen haben, die als Gruppe erstellt werden müssen, sollten sie alle den gleichen Domänencontroller verwenden, bevor Sie sie löschen.

+1

Der Datenkontext selbst ist eigentlich ziemlich leicht, obwohl er möglicherweise viele Entitäten referenzieren könnte. Es ist eine wirklich gute Idee, sie zu entsorgen, um die Entitäten zu befreien. Wenn es ein schwergewichtiges Objekt wäre, würde ich eher geneigt sein, es herumzuhalten, so dass ich es nicht neu erstellen musste. – tvanfosson

+0

@tvanfosson das ist was ich meinte; bearbeitet, um diesen Punkt klarer zu machen. Der DC kann möglicherweise viel Gewicht mit sich tragen; Am besten, um es so schnell wie möglich loszuwerden. –

+0

Argumente gegen die Entsorgung: http://stephenwalther.com/blog/archive/2008/08/20/asp-net-mvc-tip-34-dispose-of-your-datacontext-or-don-t.aspx –

0

Ich denke, das eigentliche Problem ist, dass User ist wahrscheinlich nicht der richtige Ort für einen Instanzmember Anruf GetUser.

+0

Was meinst du damit? Kannst du es weiter erklären? – EdenMachine

11

Als Rex M said soll der Datenkontext für jede logische Transaktion instanziiert, verwendet und entsorgt werden. Muster wie diese werden manchmal als "Einheit der Arbeit" bezeichnet.

Der üblichste Weg (den ich kenne), dies zu tun, besteht darin, Ihren Datenkontext in einem Verwendungsblock zu instanziieren. Ich habe VB eine Weile nicht benutzt, aber es sollte in etwa so aussehen:

Using dc As New MyDataContext() 
    user = (From u in dc.Users Where u.ID = UserID).Single() 
End Using 

Dies verstärkt nicht nur die aussehen einer Transaktion/Arbeitseinheit (durch die physische Form des Codes), aber es stellt sicher, dass Dispose() auf Ihrem Datenkontext aufgerufen wird, wenn der Block endet.

Siehe this MSDN page:

Im Allgemeinen wird eine Datacontext-Instanz ausgelegt ist, für eine „Einheit von Arbeit“ aber Ihre Anwendung dauern definiert dieser Begriff.Ein DataContext ist leicht und ist nicht teuer zu erstellen. Eine typische LINQ to SQL Anwendung erstellt DataContext Instanzen im Methodenbereich oder als Mitglied von kurzlebigen Klassen, die eine logische Gruppe von verwandten Datenbankoperationen darstellen.

0

Es gibt ein paar verschiedene Möglichkeiten, die Sie tun könnten, das wäre gute Praxis, denke ich. Zuerst können Sie ein Repository-Muster verwenden, in dem Sie das Repository nach einem Objekt abfragen, es an die Datenbank ausgeben, das Objekt abrufen, es möglicherweise vom Datenkontext trennen oder den Datenkontext abhängig von der Implementierung des Repositorys halten. und gibt es dir zurück. Die Factory-Methoden für Ihre Objekte befinden sich im Repository, nicht die Entitäten selbst. Sie würden wahrscheinlich Reflektion und Generika verwenden, um die Anzahl der zu implementierenden Methoden zu minimieren und Ihren Code DRY zu behalten.

Der andere Weg und die Art, wie LINQtoSQL nativ IMHO verwendet werden sollte, besteht darin, den Datenkontext für jede Gruppe von Datenbankoperationen zu erstellen, die Sie ausführen möchten. In diesem Fall tritt die Erstellung des Datenkontexts auch außerhalb der Entität auf, normalerweise in der Klasse, die die Entitäten verwendet, nicht in der Datenebene. Sie können dem Datenkontext auch Methoden hinzufügen - machen Sie Ihren tatsächlichen Datenkontext abstrakt und erben Sie daraus - und verwenden Sie erneut die Reflektion, um einige der üblichen Suchfunktionen auszuführen, so dass Sie sie nicht wiederholen müssen. Sie müssten wahrscheinlich ein Datenbankmuster wie ActiveRecords verwenden, bei dem die ID-Spalten immer denselben Namen haben, damit dies funktioniert.

Auf der anderen Seite könnten Sie mit nHibernate oder Castle ActiveRecord anstelle von einer der oben genannten in Ihrer eigenen Lösung zu sehen.

0

Es kann einfacher sein, wenn Sie die Benutzerklasse in Ruhe lassen und es der IDE erlauben, die Erstellung zu übernehmen.

Oft bevorzuge ich eine separate Klasse behandeln die Datenabfrage. Nehmen wir an, Sie nennen es den UserDataProvider und alle Aufrufe, um eine Benutzerinstanz zu erhalten, durchlaufen diese Klasse schließlich.

Der Konstruktor von UserDataProvider kann eine globale Instanz des Datenkontextobjekts zur Wiederverwendung instanziieren. Es würde wie folgt aussehen (in C# und ungetesteten Code so kahl mit mir):

public class UserDataProvider 
{ 
    private UserDataContext _data = null; 

    public UserDataProvider() 
    { 
     _data = new UserDataContext(); 
    } 

    public User GetUser(int userID) 
    { 
     return _data.Users.FirstOrDefault(u => u.UserID == userID); 
    } 
} 

Alternativ könnten Sie platzieren Initialisierung in einer Eigenschaft und den Zugang, dass Eigentum für die Datenkontextverwendung.

public class UserDataProvider 
{ 
    private UserDataContext _dataContext; 

    private UserDataContext DataContext 
    { 
     get 
     { 
      if (_data == null) 
       _data = new UserDataContext(); 

      return _data; 
     } 
    } 

    public User GetUser(int userID) 
    { 
     return DataContext.Users.FirstOrDefault(u => u.UserID == userID); 
    } 
}