2009-07-14 6 views
7

Meine Situation ist, dass ich im Wesentlichen vermasselt habe. Ich habe meine Codebasis vor etwa 1,5 Jahren geerbt, als ich diese Position übernahm, und anstatt das Rad neu zu erfinden, obwohl ich jetzt weiß, dass ich hätte, behielt ich die DAL in etwa der gleichen Struktur wie der vorherige Entwickler.Welche DAL-Strategie verwenden Sie oder schlagen Sie vor?

Im Wesentlichen gibt es eine Datei (jetzt bei 15k Zeilen Code), die als ein zwischen einer Reihe von DAOs, die DataSets und TableAdapters zum Abrufen von Daten verwenden, dienen. Meine xsd-Dateien sind so groß geworden, dass R # Visual Studio bei jedem Öffnen zum Absturz bringt und die Zwischenklasse, die jetzt 15k Zeilen umfasst, auch für die Analyse von R # dauern wird. Ganz zu schweigen davon, dass es hässlich ist, es funktioniert aber nicht gut und ist ein absoluter Albtraum zum Debuggen.

Was ich bisher versucht habe, ist der Wechsel zu NHibernate. NHibernate ist eine großartige Bibliothek, aber unglücklicherweise war es nicht anpassungsfähig genug, um mit meiner Anwendung zu arbeiten. Nach Aussage des Hauptentwicklers (Fabio Maulo) ist es eine Kombination aus meinen Anwendungsanforderungen und den Einschränkungen von NHibernate bei der Verwendung von Identitäten als Datenbank PK-Strategie.

Also jetzt bin ich zurück, um meine eigene DAL im Wesentlichen zu entwerfen. Ich schaue mir dafür ein paar verschiedene Muster an, möchte aber Ihre DAL-Designstrategien erhalten. Es gibt so viele Möglichkeiten und Gründe, eine DAL in einer bestimmten Weise zu implementieren. Wenn Sie also bitte Ihre Strategie erklären könnten und warum sie am besten zu Ihnen passt, würde ich das sehr schätzen.

Vielen Dank im Voraus!

Edit: Lassen Sie mich erklären, warum NHibernate nicht funktioniert, da dies die unmittelbare Antwort scheint. Meine Benutzer erstellen einen "Job", der eigentlich nur eine vorübergehende Darstellung meiner Job-Klasse ist. In diesem Job geben sie eine oder eine Liste von Gewichtungsfaktoren an, die zum Zeitpunkt der Erstellung ebenfalls vorübergehend sind. Schließlich stellen sie eine Liste von Jobdetails bereit, denen ein bestimmter Gewichtungsfaktor zugeordnet ist. Weil, in der Datenbank, Gewichtsfaktoren einzigartig sind, wenn ich den Job bestehen bleibe und es Kaskaden hinunter zum Gewichtsfaktor es stirbt, wenn es einen doppelten Gewichtsfaktor findet. Ich habe versucht, einen Check auszuführen, bevor ich den Gewichtungsfaktor dem Detail zuwies (was ich nicht machen wollte, weil ich die zusätzlichen Aufrufe an die db nicht möchte), aber CreateCriteria in NH aufzurufen, verursacht auch einen Flush in der Session, entsprechend Fabio, der meinen Cache zerstört und damit die gesamte im Speicher befindliche Darstellung des Jobs zerstört. Leute auf der NH-Mailingliste sagten, ich sollte auf GUID umsteigen, aber das ist keine machbare Option, da der Konvertierungsprozess ein Albtraum wäre.

+1

Welche Probleme haben Sie mit NHibernate? Ich benutze es mit Identität PKs die ganze Zeit ohne Problem. –

+1

Hmm, vielleicht benutzt er lange laufende Sessions (Sitzung pro Geschäftstransaktionsmodell), und in einem solchen Ansatz wird die Verwendung der Identität abgeraten, da es die Arbeitseinheit zerstört (es muss direkt nach dem Einfügen einer neuen Entität gespült werden). Eine Lösung könnte darin bestehen, die Identität zu löschen und den HiLo Identity Generator zu verwenden. –

+0

Ah ja, das ist eine Möglichkeit (und Ihre Lösung). –

Antwort

1

Meine Erfahrung mit NHibernate ist, dass, während es mit Funktionen und sehr hoher Leistung verpackt ist, Sie schließlich ein NHibernate-Experte werden müssen, um unerwartetes Verhalten zu beheben. Lesen durch die pro-NHibernate Antworten und

Hmm sehen, vielleicht nutzt er lange Lauf Sessions (Session pro Geschäfts Transaktionsmodell), und in einer solchen Ansatz, Identität unter Verwendung abgeraten, da es bricht Ihre unitofwork (es muss nach dem Einfügen einer neuen Entität direkt gespült werden). Eine Lösung könnte sein, die Identität fallenzulassen, und die HiLo Identität Generator zu verwenden.

veranschaulicht genau, was ich meine.

Ich habe eine Basisklasse erstellt, die etwas außerhalb des ActiveRecord-Musters modelliert ist, von der ich geerbt bin und die geerbte Klasse mit Attributen anerkenne, die sie an eine gespeicherte Prozedur für Select, Insert, Update und Delete anhängen . Die Basisklasse verwendet Reflection zum Lesen der Attribute und zum Zuweisen der Eigenschaftswerte der Klasse zu SP-Parametern. Im Fall von Select() weisen Sie die Spaltenwerte des Ergebnisses SQLDataReader den Eigenschaften einer Liste von Generika zu.

Dies ist, was DataObjectBase wie folgt aussieht:

interface IDataObjectBase<T> 
    { 
     void Delete(); 
     void Insert(); 
     System.Collections.Generic.List<T> Select(); 
     void Update(); 
    } 

Dies ist ein Beispiel einer Datenklasse ZUSAMMENHANG ist:

[StoredProcedure("usp_refund_CustRefundDetailInsert", OperationType.Insert)] 
    [StoredProcedure("usp_refund_CustRefundDetailSelect", OperationType.Select)] 
    [StoredProcedure("usp_refund_CustRefundDetailUpdate", OperationType.Update)] 
    public class RefundDetail : DataObjectBase<RefundDetail> 
    { 

     [StoredProcedureParameter(null, OperationType.Update, ParameterDirection.Input)] 
     [StoredProcedureParameter(null, OperationType.Insert, ParameterDirection.Output)] 
     [StoredProcedureParameter(null, OperationType.Select, ParameterDirection.Input)] 
     [ResultColumn(null)] 
     public int? RefundDetailId 
     { get; set; } 

     [StoredProcedureParameter(null, OperationType.Update, ParameterDirection.Input)] 
     [StoredProcedureParameter(null, OperationType.Insert, ParameterDirection.Input)] 
     [StoredProcedureParameter(null, OperationType.Select, ParameterDirection.Input)] 
     [ResultColumn(null)] 
     public int? RefundId 
     { get; set; } 
     [StoredProcedureParameter(null, OperationType.Update, ParameterDirection.Input)] 
     [StoredProcedureParameter(null, OperationType.Insert, ParameterDirection.Input)] 
     [ResultColumn(null)] 
     public int RefundTypeId 
     { get; set; } 

     [StoredProcedureParameter(null, OperationType.Update, ParameterDirection.Input)] 
     [StoredProcedureParameter(null, OperationType.Insert, ParameterDirection.Input)] 
     [ResultColumn(null)] 
     public decimal? RefundAmount 
     { get; set; }   
     [StoredProcedureParameter(null, OperationType.Update, ParameterDirection.Input)] 
     [StoredProcedureParameter(null, OperationType.Insert, ParameterDirection.Input)] 
     [ResultColumn(null)] 
     public string ARTranId 
     { get; set; } 

    } 

Ich weiß, es scheint, als ob ich das Rad neu zu erfinden bin, aber Alle Bibliotheken, die ich fand, waren entweder zu stark von anderen Bibliotheken abhängig (zum Beispiel ActiveRecord + NHibernate) oder waren zu kompliziert für die Verwendung und Verwaltung.

Die Bibliothek, die ich gemacht habe, ist sehr leicht (vielleicht ein paar hundert Zeilen von C#) und macht nichts mehr, als den Parametern Werte zuzuweisen und den SP auszuführen. Es eignet sich auch sehr gut für die Codegenerierung, so dass ich letztendlich keinen Datenzugriffscode schreiben werde. Ich mag auch, dass es eine Klasseninstanz anstelle einer statischen Klasse verwendet, so dass ich Daten an Abfragen ohne einige umständliche Kriterien Sammlung oder HQL weitergeben kann. Select() bedeutet "bekomme mehr wie ich".

+0

Das ist interessant, es ist ein bisschen ausführlich, aber sehr interessant. Erlaubt Ihre Strategie jedes Caching? – joshlrogers

+0

eine Sache mehr: das funktioniert auch gut mit einer Bibliothek von vorhandenen gespeicherten Procs sind keine Anforderungen, dass sie auf eine bestimmte Art und Weise benannt werden oder nicht-willkürliche Parameternamen oder Befehle haben –

+0

Ich bin ein VB-Typ der alten Schule, worum es mir geht :) Es gibt kein Caching (noch). Ich spiele mit der Idee, PostSharp zu verwenden, um das AOP-Stil-Caching zu implementieren, indem ich Methodenaufrufe abfange und gespeicherte Daten zurückschicke. Fürs Erste ist dies Lichtjahre vor dem rohen ADO.net, das sie gemacht haben. –

0

Wenn Ihre DAL auf eine Schnittstelle geschrieben wird, wäre es viel einfacher, zu NHibernate oder etwas Wechselbarem zu wechseln (Ich würde Fluent-NHibernate bevorzugen, aber ich schweife ab). Warum also nicht die Zeit dafür aufwenden, anstatt die DAL zu refaktorieren, um eine Schnittstelle zu verwenden, und dann eine neue Implementierung mit NH oder Ihrem ORM Ihrer Wahl schreiben?

1

Für mich war die beste Lösung ein ziemlich einfaches Konzept - verwenden Sie DAO-Klassendefinitionen und mit Reflektion erstellen Sie alle SQL erforderlich, um sie zu füllen und zu speichern. Auf diese Weise gibt es keine Zuordnungsdatei, nur einfache Klassen. Meine DAOs benötigen eine Entity-Basisklasse, also ist es kein POCO, aber das stört mich nicht. Es unterstützt jede Art von Primärschlüssel, sei es einzelne Identitätsspalte oder Multispalte.

+0

Verwenden Sie dies in Kombination mit einem Meta Data Mapper und/oder Data Mapper? Wie gehen Sie mit Joins oder referenzierten Klassen um? – joshlrogers

+1

@joshlrogers Kein Data Mapper - jede Tabelle wird durch eine DAO-Klasse repräsentiert. Joins werden durch Implementieren einer GetJoin-Methode in jedem DAO definiert, die die entsprechende Join-Anweisung basierend auf den anderen Tabellen zurückgibt. Jedes verbundene DAO hat eine Liste oder ein Objekt für die verbundene Tabelle. Joins werden durch Verketten von Konstruktoren zur Abfragezeit definiert - Beispiel: Liste = SQL.Read (searchCriteria, neu (Products (new Orders())) gibt eine Verknüpfung zwischen Produkten und Bestellungen zurück –

0

In den letzten Projekten haben wir aufgehört, eine separate DAL zu programmieren.

Stattdessen verwenden wir einen Object Relational Mapper (in unserem Fall Entity Framework). Wir lassen dann das Business-Layer-Programm direkt gegen das ORM.

Dies hat uns in einigen Fällen über 90% des Entwicklungsaufwands erspart.

+0

Genau deshalb wollte ich zu NHibernate wechseln Leider hat es nicht geklappt. – joshlrogers

0

Mein erster Schritt wäre, den Code aus 15 KLOC-Monstern zu brechen und dann eine Strategie für die Erstellung einer neuen DAL zu entwickeln.

0

Linq zu SQL ist nett, wenn Sie SQL Server verwenden. Es gibt eine Quelle für einen LinqToSQL-Provider für Access und MySQL. Ich habe es aber nicht getestet. LinqToSql folgt dem UnitOfWork-Modell, das der Funktionsweise von ADO.NET ähnelt. Sie führen eine Reihe von Änderungen an einer lokalen Kopie der Daten durch und übernehmen dann alle Änderungen mit einem Update-Aufruf. Es ist ziemlich sauber, denke ich.

Sie können die DataRow-Klasse auch selbst erweitern, um einen stark typisierten Zugriff auf Ihre Felder zu ermöglichen. Ich habe XSLT verwendet, um die DataRow-Nachkommen basierend auf den Metadaten jeder Tabelle zu generieren. Ich habe einen generischen DataTable-Veräußerer. MyDataTable wobei T meine abgeleitete Zeile ist. Ich weiß, dass MS stark typisierte Datensätze eine ähnliche Sache tun, aber ich wollte eine leichte generische Version, die ich die Kontrolle habe. Sobald Sie dies haben, können Sie statische Zugriffsmethoden schreiben, die die Datenbank abfragen und die DataTable füllen.

Sie wären dafür verantwortlich, die Änderungen von der DataTable zurück in die DataSource zu schreiben. Ich würde eine generische Klasse oder Methode schreiben, die das Update erstellt, einfügt und löscht.

Viel Glück!

0

Ich benutze mine Wrapper für SPs für die schnellste Datenabruf und L2S, wenn die Leistung kein Ziel ist. Meine DAL verwendet Repository-Muster und gekapselte Logik für TDD.

Verwandte Themen