Geschäftsobjekte innerhalb einer Datenzugriffsschicht

12

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 selectseine 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 DataSetsoll oder ob meine Geschäftsobjekte selbst nur eine Load()Methode haben sollen, die das erhält DataSetaus 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?


quelle
Warum haben Sie Entity Framework nicht verwendet?
Jfrankcarr
@jfrankcarr - Um ehrlich zu sein, hauptsächlich, weil ich nicht so vertraut bin, wie ich sein sollte. Ich müsste jedoch meine Tabellen überarbeiten und die richtigen Fremdschlüssel usw. hinzufügen, damit das Entity Framework die Beziehungen richtig erkennt. Würde ich aus Neugier, wenn ich es verwenden würde, die gesamte Auswahl mithilfe des Frameworks mit den Geschäftsobjekten selbst durchführen, oder würde es immer noch eine Entscheidung geben, wo diese LINQ-Abfragen abgelegt werden sollen?
Ich würde empfehlen, sich die Zeit zu nehmen, um EF zu lernen. Es kann auf den ersten Blick etwas entmutigend wirken, insbesondere wenn versucht wird, es an eine vorhandene Datenbank anzupassen, die einige bereits vorhandene Designprobleme aufweist, aber es lohnt sich.
Jfrankcarr
Sie können sich auch NHibernate ansehen, wenn Sie eine andere Option prüfen möchten.
Don 01001100
@jfrankcarr - Ich werde es auf jeden Fall untersuchen, aber wie passt es zu einer mehrstufigen Datenzugriffsanwendung? Würde das Entity Framework selbst in der DAL selbst oder in einer anderen Ebene oder sogar in den Business Objects selbst implementiert?

Antworten:

4

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.

Rachel
quelle
Es ist nicht sicher, wie von einer Ebene abhängig sein kann, um "das richtige Objekt zurückzugeben", wenn die Definition von "korrektes Objekt" in einer anderen Ebene enthalten ist.
TMN
@ TMN Das war schlecht formuliert. Ich habe den Wortlaut ein wenig geändert, weil Sie Recht haben. Der App-Code sollte wissen, nach welcher Art von Objekt er fragt.
Rachel
@ Rachel - Gotcha. Sie würden also empfehlen, dass der DAL eine Instanz von meinem Geschäftsobjekt selbst zurückgibt, richtig? Ich war etwas verwirrt über Ihren Wortlaut von "Datenobjekten", aber ich glaube, ich verstehe es. Auf diese Weise könnte mein Code ein Geschäftsobjekt von jedem Ort anfordern (nicht über sie selbst), indem er einfach anruft 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.
1
@ Scott Das ist richtig, obwohl ich die DAL - Methode so etwas wie nennen würde , Getanstatt Load, wieCustomer c = DAL.GetCustomer(id);
Rachel
2

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.

jfrankcarr
quelle
1
"Ich mag die Idee nicht, rohe Dataset-Objekte von der Datenschicht an die Geschäftsschicht zu übergeben." Dies. Tausendmal das.
Joshua Smith
@jfrankcarr - Mein DAL implementiert tatsächlich eine Schnittstelle, und ich plane Schnittstellen für alles, was Daten von Schicht zu Schicht überträgt. Daher denke ich, dass unsere Musterideen dort übereinstimmen. Empfehlen Sie mir daher, die Methoden, die das direkte Ergebnis der ExecuteScalarAbfragen zurückgeben, so zu ändern, dass Werte zurückgegeben werden, die für eine Geschäftsschicht sinnvoller sind, z bool. Ich denke anders, das ist eine sehr ähnliche Antwort wie bei Rachel.
Normalerweise gebe ich einen Booleschen Wert zum Erstellen / Aktualisieren / Löschen von Aufrufen zurück, es sei denn, ich benötige die Anzahl der betroffenen Datensätze. Zum Beispiel könnte ich ein int zurückgeben, wenn ein gespeicherter Prozess mehrere Auftragspositionen oder ähnliches verarbeitet.
Jfrankcarr
0

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.

Ryathal
quelle
0

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.

TMN
quelle