.net - net - unit of work pattern




LINQ to SQL und das Repository-Muster (2)

Ich fühle mich, als würde ich im Kreis herumrennen. Ich kann mich nicht entscheiden, was das richtige Repository-Muster mit LINQ to SQL verwendet . Wenn Sie sich mit MVC Storefront von Rob Conery auskennen, werden Sie sehen, dass seine Implementierung die LINQ-generierten Modelle mit einer anderen Klasse umschließt und die von LINQ generierte Methode einfach als Datenübertragungsobjekt (DTO) behandelt. Es sieht ungefähr so ​​aus:

//Custom wrapper class.
namespace Data
{
    public class Customer
    {
         public int Id {get;set;}
         public string Name {get;set;}
         public IList<Address> Addresses {get;set;}
    }
}

//Linq-Generated Class - severly abbreviated
namespace SqlRepository
{
    public class Customer
    {
         public int Id {get;set;}
         public string Name {get;set;}
         public EntitySet<Address> {get;set;}
    }
}

//Customer Repository
namespace SqlRepository
{
    public class UserRepository : IUserRepository
    {
        private _db = new DB(); //This is the Linq-To-Sql datacontext

        public IQueryable GetCusomters()
        {
            return
                from c in _db.Customers
                select new Customer // This is the wrapper class not the gen'd one
                {
                   Id = c.Id,
                   Name = c.Name,
                   Addresses = new LazyList(c.Addresses)
                };
        }

Was ist der Vorteil, dies auf diese Weise zu tun (mithilfe einer Wrapper - Klasse), im Gegensatz zu der Methode, die Mike Hadlow in der Verwendung des IRepository - Musters mit LINQ to SQL in seiner Version von IRepository <T> vorschlägt, wo er einfach die DTO - Objekte zurückgibt Repository?

Wo sollte die Geschäftslogik durchgesetzt und überprüft werden? Wird dies in einer separaten Ebene zusammen vom Repository bei Speichern / Aktualisieren aufgerufen oder ist es in die Wrapper-Klasse integriert?


Die Sache ist, LINQ to SQL ist kein echter Object Relation Mapper (ORM), es ist ein Datenzugriffsschichtgenerator. Sie können es zu einem ORM machen, indem Sie von Hand die XML-Dateien editieren und mit SqlMetal spielen und was nicht, aber wo es als DAL glänzt.

Die Idee hinter einem ORM ist dies. Sie haben Ihre SQL-Datenbank und Ihre Domänenobjekte. Um eine Datenbank richtig zu entwerfen, werden Sie Dinge tun (wie die Normalisierung), die logischerweise nicht in ein korrekt entworfenes Objektmodell übertragen werden und umgekehrt. Dies nennt man "Impedance Mismatch", die Rolle eines ORM besteht darin, mit diesem Mismatch sauber, effektiv und effizient umzugehen. Die weniger schmerzhafte Datenbankinteraktion ist fast eine Nebensache.

Die Idee hinter einem Repository ist, dass es alle Persistenzlogik und Abhängigkeiten von der Infrastruktur aus dem Rest Ihrer Anwendung kapselt. Wenn Ihre Anwendung ein Kundenobjekt benötigt, sollte sie nicht wissen müssen, ob sie von SQL Server, MySQL, einer XML-Datei oder einer ASP.NET-Mitgliedschaft stammt. Sobald Sie diese Entkopplung vorgenommen haben, haben alle Änderungen, die Sie an Ihrer Persistenz-Story vornehmen, keine Auswirkungen auf den Rest Ihrer Anwendung.

Vor diesem Hintergrund wird klarer, warum er getan hat, was er getan hat. LINQ to SQL wird verwendet, um die DAL zu generieren, aber das einzige, was über die DAL bekannt sein sollte, ist das Repository, also wird eine Übersetzung in seine Domänenobjekte gemacht. Auf diese Weise kann er sein Domänenmodell umgestalten, ohne sich Gedanken über seine Persistenzgeschichte machen zu müssen, und er kann seine Datenbank umgestalten, ohne sich über die Auswirkungen seiner Anwendung Sorgen machen zu müssen. Er könnte auch mit der Kodierung der Geschäftslogik beginnen, bevor er sich für Fragen entscheidet, wie ORM verwendet werden soll oder wo seine Daten gespeichert werden sollen.

Wenn er ein echtes ORM verwendet (wie NHibernate ), wird dieser Mapping-Code an anderer Stelle (entweder in XML- oder Bootstrapping-Klassen) behandelt. Ich denke LINQ to SQL (und Robs open source DAL, SubSonic ) sind großartige Projekte, aber eher für kleinere, zweischichtige Anwendungen gedacht, wo etwas wie das Repository-Muster übertrieben ist. Die Storefront ist auch ein gutes Beispiel dafür, warum die zusätzliche Komplexität von NHibernate wichtig sein kann. Er hätte sich eine Menge Code ersparen können, indem er sich mit etwas beschäftigte, das für diese Art von Szenario entwickelt wurde, anstatt alles manuell zu erledigen.


Es hängt davon ab, wo die DTOs definiert sind und wie Sie sie testen möchten. Wenn Sie DBML verwenden, möchte LINQ to SQL die Datenobjekte in der Datenschicht generieren. Während LINQ to SQL Persistenz Ignoranz unterstützt , geht es nicht aus dem Weg, um es einfach zu machen. Entity Framework unterstützt es überhaupt nicht.

Das bedeutet, dass Ihre Datenschicht im Standardmodell alle Domänenentitäten definiert. Dies ist schwierig, wenn Sie die Benutzeroberfläche / Business-Schichten in einer echten Isolation von der Datenschicht testen möchten.

Ein pragmatischer Ansatz könnte darin bestehen, die Datenobjektdefinitionen aus der Datenschicht in Komponententests zu verwenden, nicht aber den Datenkontext (dh den Datenkontext hinter der Repository-Schnittstelle auszublenden, aber die Entitätstypen zu exponieren) - aber das trübt die Gewässer ein wenig, und bedeutet, dass Ihre UI usw. die Datenschicht stark referenzieren muss. Aber wenn Sie dies als "Domänenmodellschicht, die zufälligerweise auch eine Repository-Implementierung enthält, die wir verwenden können oder nicht verwenden", könnten Sie dies rechtfertigen.

Wenn Sie vollständig getrennte Domain-Entitäten beibehalten, werden Komponententests und Inversion der Kontrolle (IoC) "reiner", aber die Menge an Code, die Sie haben (also zweischneidig), wird erhöht.





repository-pattern