Ich habe also eine Datenzugriffsschicht über TDD erstellt und bin etwas besorgniserregend geworden. Ich würde lieber nicht den falschen Weg einschlagen, also dachte ich mir, ich würde euch fragen, ob meine Gedanken mit einer sauberen Architektur übereinstimmen.
Die Methoden in meiner Datenzugriffsschicht (kurz DAL) sind ziemlich einfach. Sie stimmen mit den in der Datenbank gespeicherten Prozeduren überein (keine andere Möglichkeit, sie aufzurufen, um die Dinge sauber zu halten), und sie enthalten dieselben Parameter wie die Prozeduren. Sie stellen dann einfach eine Verbindung zur Datenbank her und geben das Abfrageergebnis zurück. Hier ist ein Beispiel:
public int DeleteRecord(int recordId)
{
recordId.RequireThat("recordId").NotZeroOrLess();
List<SqlParameter> parameters = new List<SqlParameter>();
parameters.Add(new SqlParameter { ParameterName = "@RecordId", SqlDbType = SqlDbType.Int, Direction = ParameterDirection.Input, Value = recordId});
return this.ExecuteNonQuery("DeleteRecord", parameters.ToArray());
}
Dies funktioniert perfekt für diese Art von Methode, da ich mit der Ergebnismenge nichts Sinnvolles mache. Ich möchte nur sicherstellen, dass der Befehl funktioniert, also werde ich das Ergebnis der Nichtabfrage zurückgeben, bei der es sich nur um die betroffenen Zeilen handelt, und ich kann die Logik anhand dieser Nummer überprüfen.
In einer anderen DAL-Methode möchte ich jedoch einen Datensatz laden. Meine Ladeprozedur wird für selects
eine Reihe von Tabellen ausgeführt und gibt a zurück DataSet
, aber ich kämpfe damit, ob mein DAL die Geschäftsobjekte innerhalb der Methode mit dem erstellen DataSet
soll oder ob meine Geschäftsobjekte selbst nur eine Load()
Methode haben sollen, die das erhält DataSet
aus dem DAL, und füllt sich dann im Grunde selbst aus.
Wenn Sie dies über die DAL tun, wird die Logik in den Geschäftsobjekten weniger logisch sein (obwohl dies nur eine ausgewählte Logik ist, es ist immer noch logisch), aber die DAL wird ein wenig überfüllt und es fühlt sich so an, als würde sie wirklich etwas tun, was sie nicht tun sollte. ' nicht tun.
Was denkt ihr?
Antworten:
Ihr DAL sollte Ihre Datenobjekte zurückgeben
Idealerweise sollte Ihre DAL ein "Black Box" -Objekt sein, mit dem Ihr Anwendungscode nach einem Datenobjekt fragen oder vorhandene Datenobjekte bearbeiten kann. Manchmal befindet sich zwischen der DAL und dem Anwendungscode eine weitere Ebene
Repository
, die die beiden Ebenen weiter voneinander trennt, obwohl dies nicht immer erforderlich ist.Darüber hinaus möchten Sie normalerweise nicht, dass Ihre Geschäftsobjekte sich selbst erstellen können. Dies kann zu Sicherheitslücken führen, in denen jemand Ihre Bibliothek verwenden und durch Aufrufen eine neue Instanz Ihres Objekts erstellen kann. Dabei werden
.Load(someId)
zwei Ebenen zusammengeführt, die vollständig getrennt sein sollten.Ich empfehle auch nicht, eine
.Load(DataSet ds)
Methode bereitzustellen , da Sie bei Änderungen der Datensatzdefinition die Datenobjekte, die diesen Datensatz verwenden, suchen und ändern müssen. Es ist einfacher, Ihren gesamten Datenzugriffscode an einem Ort zu speichern. Wenn Sie also die Datenzugriffsabfrage ändern, sollten Sie nur Ihre DAL-Schicht ändern müssen.quelle
BusinessObject bo = DAL.LoadRecord(id);
- klingt richtig? Die Logik zum Zuordnen der Abfrage zum BO selbst wäre in der DAL enthalten und nur dort.Get
anstattLoad
, wieCustomer c = DAL.GetCustomer(id);
Meine Methode bestand bereits vor LINQ-To-SQL und Entity Framework darin, eine Schnittstelle und eine abstrakte Klassenbibliothek zu haben, die einen "schriftlichen Vertrag" für die Kommunikation zwischen verschiedenen Ebenen der App bereitstellten. Dies wird manchmal als Ontologie bezeichnet , eine Definition für eine Arbeitsdomäne. Alles, was zwischen den Schichten passierte, verwendete diesen "Vertrag".
Ich mag die Idee nicht, rohe Dataset-Objekte von der Datenschicht an die Geschäftsschicht zu übergeben. Ich habe gesehen, dass dies zu einer Reihe von Problemen führt, insbesondere bei der Integration älterer Datenquellen. Es kann auch für neue Leute, die in ein Projekt kommen, sehr schwierig sein zu verstehen, woher Daten kommen. Schließlich muss Ihre Geschäftsschicht Daten direkt aus der Datenbank verarbeiten, was später zu Komplikationen führen kann.
Der Beispielcode, den Sie hatten, ähnelt dem Code, den ich vor LINQ hatte. Ich hatte eine gemeinsame DB-Funktionsklasse, die ich in meinen DAL-Objekten verwendet habe. Die DAL-Klassen würden die Daten lesen und in die 'Vertrags'-Objekte einpassen. Skalare Ergebnisse geben wie Ihr Löschbeispiel einen Wert zurück, normalerweise einen Booleschen Wert.
quelle
ExecuteScalar
Abfragen zurückgeben, so zu ändern, dass Werte zurückgegeben werden, die für eine Geschäftsschicht sinnvoller sind, zbool
. Ich denke anders, das ist eine sehr ähnliche Antwort wie bei Rachel.Ihr DAL sollte einen Datensatz zurückgeben. Dieser zurückgegebene Datensatz sollte das Geschäftsobjekt sein. Sie sollten nichts anderes tun müssen, als zu überprüfen, ob er die erwarteten Daten enthält. Wenn Sie mehr damit tun müssen, versuchen Sie entweder, in einer einzelnen gespeicherten Prozedur zu viel zu tun, oder Sie geben die Daten in der gespeicherten Prozedur nicht ordnungsgemäß zurück.
quelle
Ich würde empfehlen, dass Ihre Geschäftsobjekte einen Konstruktor haben, mit dem sie sich aus einer Ergebnismenge füllen können. Dadurch wird die Kopplung zwischen Ihrem DAL und der Business-Schicht aufgehoben. Wenn Sie die beiden vollständig isolieren möchten, erstellen Sie eine einfache Zuordnung von Spaltennamen => Wertepaaren aus Ihrer Ergebnismenge und übergeben Sie diese an den Konstruktor.
quelle