Frage

Als ich mehr und mehr über OOP, und beginnen zu implementieren verschiedene design-Muster, ich komme immer wieder zu Fällen, in denen Menschen hassen auf Active Record.

Menschen oft sagen, dass es nicht gut skalieren (unter Berufung auf Twitter als Ihr primäres Beispiel) - aber eigentlich niemand erklärt warum es nicht gut zu skalieren;und / oder wie zu erreichen die Vorteile von AR, ohne die Nachteile (über eine ähnliche, aber verschiedene Muster?)

Hoffentlich wird es nicht in einen Heiligen Krieg zu design patterns -- alles was ich wissen will ist ****speziell**** was ist falsch mit der Aktiven Datensatz.

Wenn es nicht gut skalieren, warum nicht?

Welche anderen Probleme gibt es?

War es hilfreich?

Lösung

Es gibt ActiveRecord-Design-Muster und ActiveRecord die Schienen ORM-Bibliothek, und es gibt auch eine Menge von knock-offs für .NET und anderen Sprachen.

Dies sind alles verschiedene Dinge.Sie Folgen meist, dass design Muster, aber erweitern und ändern es in vielen verschiedenen Arten, so, bevor hier jemand sagt "ActiveRecord Saugt" es muss qualifiziert werden, indem Sie sagen: "die ActiveRecord, es gibt haufenweise?"

Ich bin nur vertraut mit Rails' ActiveRecord, ich werde versuchen, die Adresse bei allen Beschwerden, die aufgeworfen wurden, in den Kontext der Verwendung.

@BlaM

Das problem, das ich sehe, mit Aktiven Aufzeichnungen ist, dass es immer nur über einem Tisch

Code:

class Person
    belongs_to :company
end
people = Person.find(:all, :include => :company )

Dieser generiert SQL mit LEFT JOIN companies on companies.id = person.company_id, und generiert automatisch verbundenen Unternehmen von Objekten, so dass Sie tun können people.first.company und es braucht nicht zu schlagen, die Datenbank, da die Daten bereits vorhanden.

@pix0r

Das inhärente problem mit Active Record ist, dass Datenbank-Abfragen werden automatisch generiert und ausgeführt, zum füllen von Objekten und Datenbank-Einträge ändern

Code:

person = Person.find_by_sql("giant complicated sql query")

Dies ist entmutigt, da Sie hässlich ist, aber für die Fälle, in denen Sie schlicht und einfach schreiben müssen, raw-SQL, es ist leicht gemacht.

@Tim Sullivan

...und wählen Sie mehrere Instanzen des Modells, Sie sind im Grunde ein "select * from ..."

Code:

people = Person.find(:all, :select=>'name, id')

Dies wird nur wählen Sie den Namen und die ID-Spalten aus der Datenbank, die alle anderen 'Attribute' in der zugeordneten Objekte wird einfach null, außer wenn Sie manuell laden, die Objekt, und so weiter.

Andere Tipps

Ich habe immer gefunden, dass ActiveRecord ist gut für schnelle CRUD-basierte Anwendungen, in denen das Modell ist relativ flach (wie in, nicht eine Menge von Klassenhierarchien).Jedoch, für Anwendungen mit komplexen OO Hierarchien, eine DataMapper ist wahrscheinlich eine bessere Lösung.Während ActiveRecord übernimmt ein 1:1-Verhältnis zwischen Ihren Tabellen und Ihre Daten-Objekte, welche Art von Beziehung wird unhandlich mit komplexeren Domänen.In seinem Buch-Muster, Martin Fowler weist darauf hin, dass ActiveRecord neigt dazu, zu brechen, unter Bedingungen, bei denen Ihr das Modell ist relativ Komplex, und schlägt vor, einen DataMapper als alternative.

Ich habe festgestellt, dass das wahr in der Praxis.In Fällen, in denen Sie viele Vererbung in Ihrer Domäne, es ist schwieriger, die Karte Vererbung zu Ihrem RDBMS, als es ist, Karte, Vereine oder Zusammensetzung.

Die Art, wie ich tun es wird von einer "Domäne" - Objekte zugegriffen werden, indem Sie Ihre Steuerungen über diese DataMapper (oder auch "service layer") - Klassen.Diese tun nicht direkt spiegeln die Datenbank, sondern als OO-Darstellung für einige real-Welt-Objekt.Angenommen, Sie haben eine Klasse Benutzer in Ihrer Domäne, und müssen darauf verweisen, oder die Sammlungen anderer Objekte, die schon geladen, wenn Sie Sie abrufen, das User-Objekt.Die Daten kann aus vielen verschiedenen Tabellen, und einer ActiveRecord-Muster können machen es wirklich schwer.

Stattdessen laden Sie die User-Objekt direkt und den Zugriff auf Daten mithilfe eines ActiveRecord-style-API, Ihren controller-code ruft ein Benutzer-Objekt durch aufrufen der API der UserMapper.getUser () - Methode, für Beispiel.Es ist, dass mapper, die ist verantwortlich für das laden aller zugehörigen Objekte aus Ihren jeweiligen Tabellen und Rücksendung des ausgefüllten Benutzer "Domäne" - Objekt an den Aufrufer.

Im wesentlichen sind Sie nur hinzufügen eine andere Ebene der Abstraktion, um den code besser verwaltbar.Ob Ihr DataMapper Klassen enthalten raw benutzerdefinierte SQL, oder Anrufe zu einem data abstraction layer API, oder sogar auf eine ActiveRecord-Muster, das selbst, ist nicht wirklich wichtig, um den controller-code, der den Erhalt einer schönen, bevölkert Benutzer-Objekt.

Sowieso, das ist, wie ich es mache.

Ich denke, es ist wahrscheinlich eine sehr unterschiedliche Reihe von Gründen, warum zwischen Menschen "hassen" auf ActiveRecord-und was ist "falsch".

Auf die zu hassen Problem, es gibt eine Menge von Gift gegen alles Schienen verbunden.So weit wie das, was falsch ist, ist es wahrscheinlich, dass es ist, wie alle Technik, und es gibt Situationen, in denen es ist eine gute Wahl und Situationen, in denen es gibt bessere Möglichkeiten.Die situation, wo Sie nicht bekommen, zu nehmen Vorteil von die meisten features von Rails ActiveRecord, in meiner Erfahrung, ist, wo die Datenbank ist schlecht strukturiert.Wenn Sie auf Daten zugreifen, ohne Primärschlüssel, mit Dingen, die eine Verletzung der ersten Normalform, wo es viele gespeicherte Prozeduren erforderlich, um auf die Daten zuzugreifen, sind Sie besser dran mit etwas, das ist mehr nur eine SQL-wrapper.Wenn Ihre Datenbank ist relativ gut strukturiert, ActiveRecord können Sie die Vorteile nutzen, die.

Hinzufügen, um das Thema zu Antworten, um Kommentatoren, die sagen, die Dinge sind hart in ActiveRecord mit einem code-snippet gegenerwiderung

@Sam McAfee Sagen, Sie haben eine Klasse Benutzer in Ihrer Domäne, und müssen darauf verweisen, oder die Sammlungen anderer Objekte, die schon geladen, wenn Sie Sie abrufen, das User-Objekt.Die Daten kann aus vielen verschiedenen Tabellen, und einer ActiveRecord-Muster können machen es wirklich schwer.

user = User.find(id, :include => ["posts", "comments"])
first_post = user.posts.first
first_comment = user.comments.first

Mit der include-option, ActiveRecord ermöglicht das überschreiben der default-lazy loading-Verhalten.

Meine lange und späte Antwort, auch nicht vollständige, aber eine gute Erklärung dafür, WARUM ich hasse dieses Muster, Meinungen und sogar ein paar Emotionen:

1) kurze version:Aktive Datensatz erzeugt eine "dünne Schicht"der "starke Bindung"zwischen der Datenbank und den code der Anwendung.Das löst keine logische, keine, was auch immer-Probleme, überhaupt keine Probleme.IMHO ist es nicht WERT, mit Ausnahme einiger syntaktischer Zucker für den Programmierer (die dann eventuell ein "Objekt syntax" für den Zugriff auf einige Daten, die es in einer relationalen Datenbank).Der Aufwand für das erstellen einige Komfort für den Programmierer sollte (IMHO...) besser investiert werden, die in der low-level Datenbank-access-tools, z.B.in einigen Varianten der einfache, plain hash_map get_record( string id_value, string table_name, string id_column_name="id" ) und ähnliche Methoden (natürlich sind die Konzepte und Eleganz sehr unterschiedlich mit der Sprache).

2) lange version:In einer Datenbank-getriebene Projekte, wo ich die "konzeptionelle Steuerung" der Dinge, die ich vermieden AR, und es war gut.Ich in der Regel bauen die geschichtete Architektur (Sie früher oder später tun, teilen Sie Ihre software in Schichten, zumindest in Mittel - bis großen Projekten):

A1) die Datenbank selbst, Tabellen, Beziehungen, sogar eine gewisse Logik, wenn das DBMS erlaubt es (MySQL ist auch gewachsen-bis jetzt)

A2) sehr oft, es ist mehr als ein Daten-Speicher:Datei-system (blobs in der Datenbank sind nicht immer eine gute Entscheidung ist...), die legacy-Systeme (stellen Sie sich vor, "wie" Sie zugegriffen werden, viele Varianten möglich..aber das ist nicht der Punkt...)

B) Datenbank-Zugriff-Schicht (auf dieser Ebene, Werkzeug, Methoden, Hilfsprogramme, um einfach auf die Daten in der Datenbank sind sehr willkommen, aber AR nicht bieten hier einen Wert, mit Ausnahme einiger syntaktischer Zucker)

C) Anwendung Objekte Schicht:"Anwendungsobjekte" manchmal sind die einfachen Zeilen einer Tabelle in der Datenbank, aber die meisten Zeiten, die Sie sind compound Objekte sowieso, und einige höhere Logik befestigt, so Zeit investieren in die AR-Objekte auf dieser Ebene ist schlichtweg nutzlos, eine Verschwendung von kostbaren Programmierer Zeit, denn der "wirkliche Wert", die "höhere Logik" diejenigen Objekte, die muss umgesetzt werden auf der Oberseite des AR-Objekte, jedenfalls - mit und ohne AR!Und, zum Beispiel, warum würden Sie wollen, um eine Abstraktion von "Log-Eintrag-Objekte"?App Logik-code schreibt Sie, aber sollte das haben die Fähigkeit zu aktualisieren, oder löschen Sie Sie?klingt albern, und App::Log("I am a log message") ist einige Größenordnungen einfacher zu verwenden als le=new LogEntry(); le.time=now(); le.text="I am a log message"; le.Insert();.Und für Beispiel:mit einem "Log-Eintrag Objekt" in der log-Ansicht in Ihrer Anwendung wird die Arbeit für 100, 1000 oder sogar 10000 log-Zeilen, aber früher oder später werden Sie zu optimieren, - und ich Wette, in den meisten Fällen werden Sie nur verwenden, die kleinen schönen SQL-SELECT-Anweisung in Ihrer app-Logik (die völlig unterbricht die AR-Idee..), anstelle der Verpackung, die kleine Erklärung in starre Feste AR-Idee, die Bilder mit viel code, Verpackung und Sie versteckt.Die Zeit, die Sie verschwendet mit dem schreiben und/oder an den Gebäuden AR-code hätte investiert sehr viel mehr kluge Schnittstelle zum Lesen von Listen von log-Einträge (viele, viele Möglichkeiten, der Himmel ist die Grenze).Programmierer sollten Wagen zu erfinden, neue Abstraktionen zu erkennen, Ihre Anwendungslogik, die Passform der gewünschten Anwendung, und nicht dumm zu re-implementieren silly Muster,, das klingt gut auf den ersten Blick!

D) die Anwendungslogik implementiert die Logik der Interaktion von Objekten und das erstellen, löschen und auflisten(!) der Anwendungslogik, Objekte (NEIN, diese Aufgaben sollten nur selten verankert werden, in der Anwendungslogik, Objekte selbst:tut Sie das Blatt Papier auf Ihrem Schreibtisch sagen Sie die Namen und Standorte aller anderen Blätter in Ihrem Büro?vergessen Sie "statische" Methoden für die Auflistung von Objekten, das ist albern, ein schlechter Kompromiss erstellt, um die menschliche Art zu denken passen in [einige-nicht alle-AR-Rahmen-wie-]AR-denken)

E) die user interface - also, was Schreibe ich in den folgenden Zeilen ist sehr, sehr, sehr subjektiv, aber in meiner Erfahrung, Projekte, gebaut auf AR oft vernachlässigt den UI-Teil einer Anwendung - die Zeit ist verschwendet auf die Bildung obskuren Abstraktionen.Am Ende solcher Anwendungen verschwendet viel Coder Zeit und Lust Anwendungen von Programmierern für Programmierer, tech-geneigt, innen und außen.Die Programmierer feel good (harte Arbeit endlich fertig, alles fertig und korrigieren, nach dem Konzept auf dem Papier...), und die Kunden, die "nur noch lernen, es muss so sein", denn das ist "Professionell",..ok, sorry, ich schweife ab ;-)

Gut, zugegeben, das ist alles subjektiv, aber es ist meine Erfahrung (Ruby on Rails ausgeschlossen, es kann anders sein, und ich habe null praktische Erfahrung mit diesem Ansatz).

In bezahlten Projekten, hörte ich oft die Nachfrage zu beginnen mit der Erstellung einige "active record" - Objekte, die als Baustein für die höhere Ebene der Anwendungslogik.In meiner Erfahrung, diese Auffällig oft eine Art Entschuldigung dafür, dass der Kunde (eine software dev Unternehmens in den meisten Fällen) nicht haben, ein gutes Konzept, eine große Sicht, überblick, was das Produkt schließlich sollte.Diese Kunden denken in starren Rahmen ("in dem Projekt vor zehn Jahren war es gut.."), können Sie Fleisch Einheiten, Sie können definieren von Entitäten, Beziehungen, Sie können brechen, Daten, Beziehungen und definieren Sie grundlegende Anwendung, die Logik, aber dann werden Sie aufhören und hand es über zu Sie, und denke, das ist alles, was Sie brauchen...Ihnen fehlt oft ein vollständiges Konzept von Anwendungslogik, user interface, usability-und so weiter und so weiter...Ihnen fehlt der überblick, und es fehlt die Liebe für details, und Sie möchten, dass Sie Folgen, dass AR die Art der Dinge, weil..nun, warum, er arbeitete in diesem Projekt vor Jahren, es hält die Menschen beschäftigt und schweigt?Ich weiß es nicht.Aber die "details" separates the men from the boys, oder ..wie war der ursprüngliche Werbeslogan ?;-)

Nach vielen Jahren (zehn Jahre der aktiven Entwicklung Erfahrung), wenn ein Besteller erwähnt eine "active-record-Muster", mein Wecker klingelt.Ich habe gelernt, zu versuchen, Sie zu bekommen wieder auf, dass wesentliche konzeptionelle phase, lassen Sie zweimal nachdenken, versuchen Sie, Ihnen zu zeigen, Ihre konzeptionellen Schwächen oder ganz zu vermeiden, Sie überhaupt, wenn Sie sind schonungslose (am Ende, wie Sie wissen, ist ein Kunde, der noch nicht weiß, was es will, vielleicht sogar denkt, Sie weiß aber nicht, oder versucht, Sie zu externalisieren Konzept arbeiten, um MICH gratis, kostet mich viele wertvolle Stunden, Tage, Wochen und Monate meiner Zeit, Leben ist zu kurz ...).

So, endlich:DIES ALLES ist der Grund, warum ich hasse diese dumme "active record pattern", und ich Tue, und wird es vermeiden, Wann immer möglich.

BEARBEITEN:Ich würde sogar sagen: es ist Kein Muster.Es tut nicht jedes problem lösen (Muster sind nicht dazu gedacht, zu erstellen syntaktischer Zucker).Es schafft viele Probleme:die Wurzel all seiner Probleme (erwähnt in vielen Antworten hier..) ist, dass es blendet lediglich die gute alte gut-entwickelt und leistungsstarken SQL-hinter einer Schnittstelle, die durch die Muster definition äußerst begrenzt.

Dieses Muster ersetzt Flexibilität mit syntaktischen Zucker!

Denken Sie, das problem ist AR für Sie lösen?

Einige Nachrichten sind immer mich verwirrt.Einige Antworten sind zu "ORM" vs "SQL" oder so etwas wie, dass.

Die Tatsache ist, dass AR ist nur eine Vereinfachung der Programmierung Muster, wo Sie nutzen Ihre domain-Objekte zu schreiben, es-Datenbank-Zugriff-code.

Diese Objekte haben in der Regel business-Attribute (Eigenschaften der Bohne) und einige Verhaltensweisen (Methoden, die in der Regel Arbeit auf diese Eigenschaften).

Die AR sagt nur "fügen Sie einige Methoden, um diese domain-Objekte" Datenbank-Aufgaben.

Und ich muss sagen, von meiner Meinung und Erfahrung, dass ich nicht wie die Muster.

Auf den ersten Blick kann es klingen ziemlich gut.Einige moderne Java-tools wie Spring Roo verwendet dieses Muster.

Für mich ist das eigentliche problem ist nur mit OOP Sorge.AR-Muster zwingt Sie in einige Weg, um eine Abhängigkeit von Ihrem Objekt zu infraestructure Objekte.Diese infraestructure Objekte lassen Sie das domain-Objekt für die Abfrage der Datenbank über die Methoden vorgeschlagen, von AR.

Ich habe immer gesagt, dass zwei Ebenen sind der Schlüssel für den Erfolg eines Projekts.Die service-Ebene (wo die bussiness Logik wohnt oder exportiert werden können, die durch irgendeine Art der remoting-Technologie, die als Web-Services, für Beispiel) und die domain-Schicht.Meiner Meinung nach, wenn wir hinzufügen einige Abhängigkeiten (nicht wirklich notwendig), um die domain-Schicht-Objekte für die Lösung der AR-Muster, unsere domain-Objekte wird schwieriger sein, zu teilen mit andere Ebenen oder (selten) externe Anwendungen.

Frühling Roo Umsetzung von AR ist interessant, weil es sich nicht auf das Objekt selbst, sondern in einigen AspectJ-Dateien.Aber wenn Sie später nicht arbeiten wollen mit Roo und umgestalten das Projekt, das AR-Methoden implementiert werden, die direkt in Ihrem domain-Objekte.

Eine andere Sicht.Vorstellen, dass wir tun nicht verwenden eine Relationale Datenbank zum speichern von unserer Objekte.Stellen Sie sich die Anwendung speichert unsere domain-Objekte in einer NoSQL-Datenbank oder nur in XML-Dateien, zum Beispiel.Würden wir implementieren Sie die Methoden, diese Aufgaben in unsere domain-Objekte?Ich denke nicht (für Beispiel, in die Fall von XM, wir würden hinzufügen von XML-bezogenen Abhängigkeiten, um unsere domain-Objekte,...Wirklich traurig, denke ich).Warum machen wir es dann umsetzen müssen, das relationale DB-Methoden in der domain-Objekte, die Ar-Muster sagt?

In der Summe der AR-pattern klingen kann einfacher und gut für kleinen und einfachen Anwendungen.Aber, wenn wir komplexe und große apps, ich glaube, der klassische mehrschichtige Architektur ist ein besserer Ansatz.

Die Frage ist, über die Aktive Record design pattern.Nicht ein orm Werkzeug.

Die ursprüngliche Frage markiert mit Schienen und bezieht sich auf Twitter, die ist gebaut in Ruby on Rails.Die ActiveRecord-framework innerhalb von Schienen ist eine Implementierung von Fowler ' s Active Record design pattern.

Die Hauptsache ist, dass ich gesehen habe, mit Bezug auf Beschwerden über Active Record ist, dass, wenn Sie ein Modell erstellen um eine Tabelle, und wählen Sie mehrere Instanzen des Modells, Sie sind im Grunde ein "select * from ...".Dies ist gut für die Bearbeitung einer Aufzeichnung, oder anzeigen einer Aufzeichnung, aber wenn Sie wollen, sagen, zeigen Sie eine Liste der Städte, die für alle Kontakte in Ihrer Datenbank, die Sie tun könnten ", wählen Sie die Stadt von ..." und nur die Städte.Sie tun dies mit Aktiven Datensatz würde erfordern, dass Sie die Auswahl aller Spalten, aber nur mit der Stadt.

Natürlich, unterschiedliche Implementierungen handhaben dies anders.Dennoch, es ist ein Problem.

Jetzt, Sie können dies umgehen, indem Sie eine neue Modell für die spezifische Sache, die Sie versuchen zu tun, aber einige Leute würden argumentieren, dass es mehr Aufwand als nutzen.

Mir, ich Grabe Aktiven Datensatz.:-)

HTH

Ich Liebe die Art, wie SubSonic macht das eine Spalte einzige.
Entweder

DataBaseTable.GetList(DataBaseTable.Columns.ColumnYouWant)

, oder:

Query q = DataBaseTable.CreateQuery()
               .WHERE(DataBaseTable.Columns.ColumnToFilterOn,value);
q.SelectList = DataBaseTable.Columns.ColumnYouWant;
q.Load();

Aber Linq ist immer noch der König, wenn es um lazy loading.

@BlaM:Manchmal ich möchte implementiert einen aktiven Datensatz in ein Ergebnis einer Verknüpfung.Nicht immer auf das Verhältnis Tabelle <--> Aktive Datensatz.Warum nicht "Ergebnis der Join-Anweisung" <--> Active Record ?

Ich werde darüber sprechen, Active Record design pattern, ich habe nicht gesehen, ROR.

Einige Entwickler hassen Aktiven Datensatz, weil Sie schlau Lesen Bücher über das schreiben sauber und ordentlich-code, und diese Bücher, die besagt, dass active record verstößt single resposobility Prinzip verstößt DDD Regel, die domain-Objekt sollte hartnäckig unwissend, und viele andere Regeln von dieser Art von Büchern.

Die zweite Sache, die domain-Objekte in Active Record neigen dazu, werden 1-zu-1 mit database, das betrachtet werden kann, eine Einschränkung in irgendeiner Art des systems (n-tier meistens).

Das ist nur abstrakte Dinge, ich habe nicht gesehen, ruby on rails tatsächliche Implementierung dieses Musters.

Das problem, das ich sehe, mit Aktiven Aufzeichnungen ist, dass es immer nur um eine Tabelle.Das ist okay, solange Sie wirklich nur, dass einem Tisch, aber wenn Sie die Arbeit mit Daten in den meisten Fällen werden Sie haben einige Art der Verknüpfung irgendwo.

Ja, join in der Regel ist schlimmer als keine join an alle wenn es um Leistung, sondern join in der Regel ist besser als "fake" join vom ersten Lesen der gesamten Tabelle Ein und verwenden Sie dann die gewonnenen Informationen zu Lesen und zu filter-Tabelle B.

Das problem mit ActiveRecord ist, dass die Abfragen, die automatisch für Sie generiert, können Leistungsprobleme verursachen.

Sie tun etwas unintuitiv tricks zur Optimierung der Abfragen, lassen Sie sich Fragen, ob es wäre besser gewesen, die Zeit effektiv zu schreiben, die Abfrage von der hand in den ersten Platz.

Obwohl all die anderen Kommentare bezüglich SQL-Optimierung sind sicherlich gültig, meine größte Beschwerde mit dem active record-Muster ist, dass es führt in der Regel zu impedance mismatch.I like keeping my domain sauber und ordentlich gekapselt, die die active record-Muster in der Regel zerstört alle Hoffnung zu tun.

Versuchen Sie es zu tun eine viele zu viele polymorphe Beziehung.Gar nicht so einfach.Vor allem, wenn Sie nicht mit STI.

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