Frage

Ich entwarf zunächst mein System nach der s # Architektur Beispiel in diesem Codeproject Artikel beschrieben (Leider bin ich mit NHibernate nicht). Die Grundidee besteht darin, dass für jedes Domain-Objekt, das mit der Persistenz-Schicht müßte kommunizieren Sie ein entsprechendes Datenzugriffsobjekt in einer anderen Bibliothek haben würden. Jede Data Access Object implementiert eine Schnittstelle, und wenn ein Domain-Objekt Zugriff auf eine Datenzugriffsmethode muss es immer Codes gegen eine Schnittstelle und nie gegen die DAOs selbst.

Zu der Zeit, und noch, dachte ich, das Design sehr flexibel. Da jedoch die Menge von Objekten in meinem Domain-Modell ist gewachsen Ich finde mich in Frage zu stellen, ob es hier nicht ein organisatorisches Problem ist. Zum Beispiel endet fast jedes Objekt in der Domäne mit einem entsprechenden Datenzugriffsobjekt und Data Access Object-Schnittstelle auf. Nicht nur das, aber jeder von ihnen ist an einem anderen Ort, die schwieriger zu pflegen, wenn ich um einige Namensräume etwas Einfaches wie Verschiebung tun will.

Interessanterweise sind viele dieser DAOs (und ihre entsprechenden Schnittstellen) sind sehr einfach Kreaturen - die häufigste nur eine einzige GetById () -Methode. Ich am Ende mit einem ganzen Bündel von Objekten bis wie

public interface ICustomerDao {
  Customer GetById(int id);
}

public interface IProductDao {
  Product GetById(int id);
}
public interface IAutomaticWeaselDao {
  AutomaticWeasel GetById(int id);
}

Wo ihre Implementierer sind in der Regel auch sehr trivial. Das hat mich gefragt, ob es nicht einfacher wäre, in eine andere Richtung zu gehen, vielleicht meine Strategie Schalten durch ein einzelnes Objekt für einfachen Datenzugriff Aufgaben hat, und die Schaffung von speziellen Data Access Objects für diejenigen reserviert, die ein wenig mehr etwas brauchen kompliziert.

public interface SimpleObjectRepository {
      Customer GetCustomerById(int id);
      Product GetProductById(int id);
      AutomaticWeasel GetAutomaticWeaselById(int id);
      Transaction GetTransactioinById(int id);
}
public interface TransactionDao {
  Transaction[] GetAllCurrentlyOngoingTransactionsInitiatedByASweatyGuyNamedCarl();
}

Hat jemand Erfahrung mit einer Architektur, wie dies hat? Insgesamt bin ich mit dem Set-up sehr glücklich, wie es jetzt sein Management all dieser kleinen Dateien meine einzige Sorge ist. Ich frage mich jedoch immer noch, was andere Ansätze in Richtung auf die Data Access Layer Strukturierung vorhanden sein.

War es hilfreich?

Lösung

Ich empfehle gegen den einfachen Ansatz anders als in einfachen Systemen, in der Regel denke ich, Sie besser ein eigenes Repository für jedes Aggregat zu schaffen und so viel geeignete Logik, wie Sie können innerhalb es eingekapselt wird.

Also mein Ansatz wäre ein Repository für jedes Aggregat zu haben, die es, wie CustomerRepository braucht. Dies würde eine Add (Speicher) Methode hat und, falls geeignet für das Aggregat, ein Entfernen (Löschen) Methode. Es wäre auch jede andere benutzerdefinierte Methoden, die einschließlich Abfragen (GetActive) gelten und vielleicht einige dieser Abfragen könnten Spezifikationen akzeptieren.

Das klingt nach viel Aufwand, aber andere als die benutzerdefinierte Abfragen Großteil des Codes ist, zumindest wenn man ein modernes ORM verwenden, sehr einfach zu implementieren, so verwende ich Vererbung (ReadWriteRepositoryBase where T: IAggregateRoot) und / oder Zusammensetzung (Aufruf zu einer RepositoryHelper Klasse out). Die Basisklasse könnte Methoden, die in allen Fällen, wie GetById gelten.

Hope, das hilft.

Andere Tipps

Ich arbeite in PHP, aber ich habe etwas ähnliches Set für meine Datenzugriffsschicht. Ich habe eine Schnittstelle implementiert, die etwa wie folgt aussieht:

interface DataAccessObject
{
public static function get(array $filters = array(), array $order = array(), array $limit = array());
public function insert();
public function update();   
public function delete();
}

Und dann so etwas wie dies jedes meiner Datenzugriffsobjekte arbeiten:

class DataAccessObject implements DataAccessObject
{
    public function __construct($dao_id = null) // So you can construct an empty object
    {
        // Some Code that get the values from the database and assigns them as properties
    }
    public static function get(array $filters = array(), array $order = array(), array $limit = array()) {};  // Code to implement function
    public function insert() {};  // Code to implement function
    public function update() {};  // Code to implement function 
    public function delete() {};  // Code to implement function        
}

Ich bin derzeit der Aufbau jedes der Datenzugriffsobjektklassen manuell so, wenn ich eine Tabelle hinzufügen oder eine vorhandene Tabelle in der Datenbank ändern, natürlich muß ich den neuen Code von Hand schreiben. In meinem Fall ist dies immer noch ein großer Schritt, von wo aus unserer Codebasis war.

Sie können jedoch auch die SQL-Metadaten verwenden (unter der Annahme, dass Sie ein ziemlich Sound Datenbank-Design haben die Vorteile von Fremdschlüssel-Constraints und dergleichen nimmt), um diese Datenzugriffsobjekte zu erzeugen. Dann in der Theorie, könnten Sie eine alleinerziehende Mutter DataAccessObject-Klasse verwenden, um die Eigenschaften und Methoden der Klasse zu konstruieren und sogar Beziehungen zu den anderen Tabellen in der Datenbank automatisch zu erstellen. Dies würde mehr oder weniger erreichen die gleiche Sache, die Sie beschreiben, sind denn dann könnte man die DataAccessObject Klasse erweitern benutzerdefinierte Methoden und Eigenschaften für Situationen zu schaffen, die eine gewisse Menge an manuell erstellten Code.

Als Nebenbemerkung für .NET-Entwicklung, haben Sie sich einen Rahmen, der die darunter liegende Struktur der Datenzugriffsschicht Griffe für Sie, wie Subsonic? Wenn nicht, würde ich empfehlen, eine solche Suche in nur einem Rahmen: http://subsonicproject.com/ .

oder für PHP-Entwicklung, ein Framework wie Zend Framework würde eine ähnliche Funktionalität bieten: http://framework.zend.com

George Ich weiß genau, wie Sie sich fühlen. Billys Architektur macht Sinn für mich, aber die Notwendigkeit, einen Behälter zu schaffen, Imapper und Mapper-Dateien sind schmerzhaft. Dann, wenn Sie NHibernate die corrosponding .hbm-Datei verwenden und in der Regel ein paar Unit-Test-Scripts zu überprüfen every arbeiten.

Ich gehe davon aus, dass, obwohl Ihr nicht NHibernate mit Ihrem noch eine generische Basisklasse lo Last mit / speichern Sie Ihre Container d

public class BaseDAO<T> : IDAO<T> 
{
     public T Save(T entity)
     { 
       //etc......
     }
}
public class YourDAO : BaseDAO<YourEntity>
{
}

Ich denke, das ohne NHibernate würden Sie Reflexion oder eine andere machanism verwenden, um zu bestimmen, welche SQL / SPROC anrufen?

Eitherway, meine Gedanken zu diesem Thema wäre, wenn DAO nur die grundlegenden CRUD-Operationen in der Basisklasse definierten ausführen muß, dann sollte es nicht nötig sein, individuellen Mapper und Schnittstellen zu schreiben. Der einzige Weg, ich denke, kann dies von achiving ist Reflection.Emit zu verwenden, um dynamisch Ihre DAO on the fly zu erstellen.

Ich verwende auch das Repository-Muster für meine DAO und ich bin ganz zufrieden damit. Ja, Sie am Ende mit ganz wenigen kleinen Klassen, aber es ist sehr wartbar. Es ist ein bisschen stärker, wenn Sie die IQueriable Schnittstelle (LINQ). Sie auch Generika (So etwas wie T GetById<T>(int id)) verwenden können, wenn Sie eine ziemlich konsistente Datenbankstruktur haben.

Der Haupt mit dem zweiten Ansatz ist in der Unit-Tests zurückziehen - große Fabrik Methoden spöttisch aus wie Ihre SimpleObjectRepository mehr Arbeit erfordern als nur ICustomerDao spöttisch aus. Aber geht mein Projekt mit dem zweiten Ansatz eng miteinander verwandte Objekte (wo die meisten werden in allen Unit-Tests verwendet werden), weil sie die mentale Belastung aufhellt und macht es besser wartbar.

Ich würde herausfinden, was Ihr System, dass mehr wartbar und leicht zu verstehen und zu tun macht.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top