3 Stimmen

Wie wird der Objekttyp von der Geschäftsschicht an die Datenschicht übergeben?

Ich erstelle eine n-tier Anwendungsarchitektur. Verschiedene Schichten weiß nichts von jeder anderen internen Implementierungen und die Kommunikation zwischen Schichten wird Trog sehr enge Schnittstellen mit IoC/DI unterstützt behandelt.

Jetzt übergebe ich Geschäftsobjekte (definiert in der Geschäftsschicht) an die Datenschicht. Die Geschäftsschicht selbst weiß nicht, wie und wo die Daten tatsächlich gespeichert werden (normalerweise in der Datenbank, aber die Geschäftsschicht sollte das nicht wissen). Die Geschäftsobjekte werden durch die Implementierung von IDataReader an die Datenschicht übergeben (dieser Ansatz unterstützt auch das Massenladen von Daten in zukünftigen Szenarien). Die Datenschicht liest alle Daten aus IDataReader und ruft eine gespeicherte Prozedur auf, um die Daten in der Datenbank zu speichern (wenn ein Objekt gespeichert wird, gibt IDataReader "eine Zeile" zurück).

Das eigentliche Problem liegt hier:

Weil ich gerade IDataReader an die Datenschicht übergeben und Daten von seinem Typ zu trennen, was ist der beste Weg in diesem Fall zu bestimmen, Ort der Daten?

Wenn ich zum Beispiel ein aktuelles Geschäftsobjekt vom Typ "Benutzer" an die Datenschicht übergebe, dann sollte die Datenschicht die Daten in der Tabelle "Benutzer" speichern. In anderen Fällen können die Daten unabhängig vom Typ in der Geschäftsschicht in einer anderen Struktur gespeichert werden.

In der aktuellen Implementierung übergebe ich Typinformationen des Geschäftsobjekts an die Datenschicht und die Datenschicht prüft diesen Typ und entscheidet, wo die Daten platziert werden sollen.

Ist es die richtige Lösung, um Datenschicht inspizieren eingehende Daten und bestimmt seinen Platz oder sollte Datenschicht expose Liste der "Orte", wo Daten gespeichert werden können (enum?)?

Vielen Dank im Voraus!

/Klarstellung :

Die Optionen, die ich hier sehe, sind: 1. Datenebene bietet eine Liste von "Plätzen", auf denen Daten gespeichert werden können 2. Die Datenebene prüft die gegebenen Argumente (wie den Typ arg) und bestimmt, wo die Daten gespeichert werden

Erste Option: Was passiert, wenn ich versuche, ein Geschäftsobjekt vom Typ "Produkt" in einer Struktur zu speichern, die normalerweise vom Typ "Benutzer" verwendet wird?

Zweite Option Strafe; Ich muss den Typ "Namespace1.Namespace2.User" einer bestimmten Routine zuordnen, die ihre Daten in der Tabelle "User" speichert. Also manuell tun einige Zuordnung für JEDEN Typ...

/Klarstellung 2:

Jetzt rufe ich sie auf diese Weise ab:

service.Retrieve(typeof(Catalog), null, catalogArgs, e => catalogConverter.Read(e));

Ich übergebe also typeof(Catalog) an die Datenschicht... so habe ich Typinformationen in der Datenschicht.

Jetzt in der Datenschicht muss ich "Adapter" auswählen, die harte Arbeit, um Daten aus der Datenbank zu erhalten tut. Ich kann eine enorme if/switch-Struktur schreiben, um den Adapter auszuwählen ... was frustrierend ist. Ich kann auch ein Attribut schreiben und es wie folgt verwenden:

[TypeAdapterAttribute("Namespace1.Namespace2.Catalog, and assembly info...")]
class CatalogAdapter { ... }

Dann habe ich Code, der Mapping von gegebenen Typ zu Attributwert tut...

...aber es ist ein wenig aufgebläht und problematisch mit diesem hart kodierten Typ String...

Irgendwelche Vorschläge...?

/Klarstellung 3

Ich habe die Idee, dass dieses System durch "steckbare Geschäftsmodule" erweitert werden kann. Diese Module enthalten Geschäftsobjekte (und einige Logik), die von der Basis-Geschäftslogik nicht bekannt sind, und auch die Datenschicht weiß nichts von diesen Geschäftsobjekten, die in "gesteckten Baugruppen" enthalten sind. Dieses externe Geschäftsmodul hat keinen Bezug zur Basis-Business-Schicht oder zur Datenschicht. Wenn ein Geschäftsobjekt aus dieser externen Baugruppe gespeichert wird (=an die Datenschicht gesendet wird), speichert die Datenschicht es standardmäßig automatisch in einer Datenstruktur im EAV-Stil (http://en.wikipedia.org/wiki/Entity%E2%80%93attribute%E2%80%93value\_model). Da diese Art von Datenstruktur zu Leistungsproblemen führen kann, muss die Datenschicht die Möglichkeit haben, bestimmte Geschäftsobjekttypen in einer eigenen Datenstruktur zu speichern (normalerweise eine Tabelle mit einer Eins-zu-Eins-Zuordnung zu diesem Typ). Hier stellt sich also das Problem, wie man diese "Auswahlentscheidung" implementiert :)

Die Idee ist, dass ich viele neue Geschäftsobjekte erstellen und alle in der Datenschicht speichern kann, ohne etwas in der Datenschicht zu codieren! Zu einem späteren Zeitpunkt kann ich bei Bedarf eigene Datenstrukturen für ausgewählte Geschäftsobjekte erstellen.

1voto

Wenn Sie eine eigene Datenbankschicht erstellen möchten, die nicht mit der Geschäftsschicht verbunden ist, können Sie auch eine separate Assembly mit Verträgen einführen

List<Customer> customers = DB.LoadCustomers();

Die Datenschicht kann mit generischen Typparametern arbeiten und Informationen über das Geschäftsobjekt über Reflection . Dies ermöglicht eine gute Trennung der Schichten, da die Datenschicht keinen Bezug zu Geschäftskomponenten benötigt.

List<Customer> customers = DataContext.Query<Customer>.Load();

o

Customer customer = DataContext.Query<Customer>.Load(custID);

O/R-Mapper funktionieren in der Regel wie folgt

List<Customer> customers = Context.Query<Customer>()
    .Where(cust => cust.Name.StartsWith("A"))
    .OrderBy(cust => cust.Name)
    .ToList();

In diesen Beispielen erstellt und füllt die Datenschicht die Geschäftsobjekte. Ansonsten muss die Geschäftsschicht die Namen der Tabellenspalten kennen.

(Hinweis: Ich beziehe mich hier nicht auf bestimmte Datenschnittstellen).


UPDATE:

Wenn Sie Ihre eigene Datenbankschicht erstellen möchten, die nicht mit der Geschäftsschicht verbunden ist, können Sie auch eine separate Assembly mit Verträgen einführen

public interface ICustomer
{
    string LastName { get; set; }
    string FirstName { get; set; }
    ...
}

Sowohl die Datenschicht als auch die Geschäftsschicht hätten einen Verweis auf diese Verträge.

In der Datenschicht würden Sie eine Methode ähnlich der folgenden haben

public List<T> LoadAll<T>(Func<T> create)
{
    var list = new List<T>();
    if (T is ICustomer) {
        string sql = "SELECT * FROM tblCustomer";
        ...
        while (reader.NextResult()) {
            ICustomer cust = (ICustomer)create();
            cust.FirstName = reader.GetString("FirstName");
            ...
            list.Add((T)cust);
        }
    } else if (T is IOrder) {
        ...
    }
    return list;
}

In der Geschäftsschicht würden Sie schreiben

List<ICustomer> customers = DbLayer.LoadAll<ICustomer>(() => new Customer());

Jetzt kann Ihre Datenschicht mit Kunden arbeiten, ohne Ihre Kundenklasse zu kennen und ohne einen Verweis auf die Assembly der Geschäftsschicht zu haben.

0voto

David Punkte 3608

Ich würde Ihnen empfehlen, ein ORM (Entitiy Framework, NHibernate) oder ein Mikro-ORM (PetaPoco, Dapper) zu verwenden, um Ihre Objekte auf Datenspeicher abzubilden.
Schauen Sie sich das an und schicken Sie mir eine E-Mail, wenn Sie eine konkrete Frage haben.

UPDATE: Ich glaube, ich habe gerade verstanden, was Sie fragen.
Sie müssen für jeden Typ eine neue Methode in Ihrer Datenschicht definieren. So:

public User GetUserById(int id);
public void SaveUser(User user);
public Product GetProductById(int id);
public void SaveProduct(Product product);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X