Thread Catalyst - DBIx::Class - Model - Diskussion (3 answers)
Opened by sid burn at 2009-02-01 17:39

sid burn
 2009-02-21 17:26
#119063 #119063
User since
2006-03-29
1520 Artikel
BenutzerIn

user image
Hi,
erstmal Sorry für die etwas verspätete Antwort. Dachte das würde evtl. mehr Leute Interessieren und der eine oder andere würde dazu noch was schreiben. Nunja eine "Best Bractices" Diskussion scheint die meisten bei Perl ja nicht zu Interessieren. ;)

Quote
ist die spalte "user" in deinem modell der primary key? denn dann geht auch einfach
$schema->find($pk), was unabhangig vom namen des PK ist.

Hmm, jaein.
Das sollte nur ein Beispiel sein. Ich persönlich würde ein VARCHAR Feld sowie nicht als PK nehmen, aber username wohl als UNIQUE Key. Und find() Funktioniert ja auch mit einem UNIQUE Key, wodurch es rein Theoretisch geht. Ein Freund davon bin ich aber trotzdem nicht. Denn wenn die Datenbank erweitert wird kann es ja durchaus vorkommen das man Felder durchsucht die man nicht durchsuchen wollte und es mehr als ein match geben kann.

Ich sage es mal in deinen Worten. Ich bin diesbezüglich faul und tippe es sofort ganz ein um mir mögliche Probleme oder Fehlersuche in der Zukunft zu ersparen.

Oder was passiert z.B wenn ein benutzer als Username "2000" hat und ich langsam auf die 2000 benutzer zu gehe und ich dein weg nutze? (wenn ich ein PK "id" auto_increment habe).

Quote
verstehe ich nicht. wenn du die spalte in der datenbank änderst, musst du noch lange nicht
den hashkey auch umbenennen. das definiert man ja alles im schema.

Du meinst wenn du im Schema bei "add_column(s)" den "accessor" Hash key änderst? Okay das wäre eine Möglichkeit an der ich nicht gedacht habe.

Quote
und jetzt sag mir mal, wo der unterschied ist (halb pseudo-code):

Code: (dl )
1
2
3
$dbic->find({ user => $user });
vs.
$dein_modell->find_user($user);


Im ersten Beispiel gehst du hin und bekommst ein DBIx::Class Objekt zurück und du benutzt direkt das interne Interface von DBIx::Class. Im unteren Beispiel gibt es eine Methode "find_user" die einen Benutzer findet. Wie es diesen aber findet hängt vom Model ab.

Im unteren beispiel kann ich z.B. einfach den Datenspeicher ändern. Die Daten liegen in einer CSV Datei? In einer XML Datei? Oder in ....? Im letzten Beispiel problemlos machbar. Im oberen musst du praktisch alle Funktionalitäten von DBIx::Class nachbauen um sicher zu sein das du nichts kaputt machst, sofern du DBIx::Class wechseln solltest bzw etwas anderes nutzt. Wenn es natürlich nur das find() in diesem Beispiel ist, dann ist das ja nicht allzu kompliziert, nur können search() und andere Routinen von DBIx::Class schon ziemlich kompliziert werden. Und viele Sachen ergeben evtl. bei einem anderen Datenspeicher keinen Sinn. "prefetch" um eine andere tabelle zu laden, oder join Statements auf einer XML Datei?

Das erste Beispiel wäre vergleichbar als wenn du ein Model hast sagen wir mal das auf CSV Basiert und ein "$c->model('User')" würde dir direkt ein Text::CSV_XS Objekt zurück geben. Oder eben ein DBI Objekt oder eben in diesem Fall ein DBIx::Class Objekt. Kurz gesagt, was ist daran ein Model? Absolut gar nichts!

Gehen wir mal zur Komplizierten sachen (Aus der Doku von "DBIx::Class::ResultSet").

Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 $rs = $schema->resultset('Person')->search(
undef,
{
alias => 'mother', # alias columns in accordance with "from"
from => [
{ mother => 'person' },
[
[
{ child => 'person' },
[
{ father => 'person' },
{ 'father.person_id' => 'child.father_id' }
]
],
{ 'mother.person_id' => 'child.mother_id' }
],
]
},
);

# Equivalent SQL:
# SELECT mother.* FROM person mother
# JOIN (
# person child
# JOIN person father
# ON ( father.person_id = child.father_id )
# )
# ON ( mother.person_id = child.mother_id )


Wenn du soetwas im Controller hinschreibst was ist den dann noch der Sinn deines Models? Was abstrahiert den dann noch dein Model? Den ganzen Aufruf hiervon steht direkt im Controller, und dadrunter wird ja sogar gezeigt wie es im SQL ausschauen würde. Ob du nun im Controller hingehst und dann dort obiges hinschreibst oder eben ob du das SQL direkt hinschreibst (weil dein Model pures DBI ist) macht keinen großen Unterschied mehr.

Ein echtes Model hast du einfach nicht dadurch. Ein Model das ja eigentlich den Datenzugriff intern machen soll wovon du nichts siehst und das es für dich abstrahiert. Mit dem Sinn dahinter das du das Model ohne Probleme erweitern/austauschen kannst ohne das deine Applikation bricht.

Eine eigene ResultSet Class zu machen wäre schonmal der Anfang, und obrige Sache in eine Methode zu packen die du dann nur noch aufrufst. Das hat dann auch den Vorteil das das geschriebene wiederwendbar ist, und solltest du am Statement irgendwo etwas anfassen müssen änderst du es Zentral an einer Stelle. Nicht in evtl. fünf Stellen in irgendwelche Controller.

Es stellt sich hier nur die Frage. Wieviel musst du letztendlich tun damit du wirklich ein Model hast? Nur bei komplizierten Sachen?

Quote
das schöne ist ja, dass du sowas ein einziges mal im schema definierst.
nach deinem modell müsste man fur jede spalte eine eigene methode schreiben.

Hmm, nein. Ein find() geht ja nur auf PKs oder UNIQUE Keys warum sollte ich dann für jede Spalte eine eigene Methode schreiben? Und auch so macht es kein Sinn, warum sollte ich z.B. ein find_password() hinzufügen? Schonmal einen Eintrag anhand seines Passwortes ausgelesen?

Quote
wenn du gerne solche methoden schreibst, hält dich natürlich niemand davon ab,
aber ich bin da eher faul.

Naja du solltest ja selber Wissen das es zwei arten von Faulheit gibt.

Einmal die Faulheit es vernünftig zu machen und es schnell Quick & Dirty zu machen womit man sich im Moment sehr viel Zeit spart.

Und einmal das Faul sein womit man es gleich von Anfang an richtig macht. Aber sich dann in Zukunft viel Arbeit erspart.

Das letztere Faul sein ist ja eher das was man anstreben sollte, nicht das erste.

Ich möchte hier darüber Diskutieren welcher Weg besser ist. Da ich mir darüber selber noch nicht ganz sicher bin. Den weg den du gehst kommt mir aber nicht toll vor. Mein weg aber auch nicht da es evtl. viel schreibarbeit erfordert und einen hohen aufwand. Die Frage ist halt eher mache ich es "Best Practices" schreibe ich ein Model das wirklich den namen "Model" verdient, oder nutze ich einfach was da ist. Habe es zwar jetzt einfach, und komme schnell zum Ziel, verzichte dann aber darauf wirklich das "Model" austauschen zu können und es nicht mehr groß verändern zu können. Und wenn ich es doch mache was muss ich alles beachten damit ich wirklich ein Model habe?

Der Weg, einfach nur das Schema erzeugen und DBIx::Class direkt zu nutzen ist für mich kein echtes Model.

Vergleichbar hierzu kann man auch sagen. Warum so viel schreibarbeit und ein Model, View Controller voneinander trennen? Hey ich mache alles im View, SQL auslesen, keine Abstraktion und baue dort direkt das HTML auf. Also praktisch PHP. Ist am kürzesten und geht wohl am schnellsten...




Auch eine andere kleine Diskussion die ich mit meinen Arbeitskollegen vor kurzem hatte ist z.B. die Verwendung von HTML::FormFu.

Sicherlich ist es nett, aber die ganze Validierung die es macht ist eigentlich im Controller an der falschen Stelle.

Wenn ich Beispielsweise einen benutzer habe mit "uid", "gid", "email" etc. und nur bestimmte ranges erlaubt sind warum sollten diese in HTML::FormFu stehen? Die gültigkeit der Werte gehört doch eigentlich in das Model. Das Model selber muss Wissen welche Werte gültig sind, und nicht irgendeine Controller Methode.

Das hat dann auch den Vorteil wenn sie im Model sind das man sie nicht "vergessen" kann.

Zumal bei manchen Validierungen eh das Model befragt werden muss. z.B. "Gibt es den benutzer schon?" oder ob Felder wirklich "Unique" sind etc.

So wie es eigentlich sein müsste ist man bekommt die Daten vom benutzer, fügt sie mithilfe des Modells hinzu, und das klappt dann oder es gibt zurück was nicht klappte und warum, und man präsentiert dies im Fehlerfall dem benutzer.


Wie ich letzteres aber umsetze weiß ich auch noch nicht genau. Alle Methoden zum Setzen/Lesen überschreiben? Die "Inflate/Defalte" sachen nutzen die DBIx::Class bietet? Oder hat DBIx::Class noch mehr möglichkeiten, muss ich mich damit mal mehr auseinander setzen.
Nicht mehr aktiv. Bei Kontakt: ICQ: 404181669 E-Mail: perl@david-raab.de

View full thread Catalyst - DBIx::Class - Model - Diskussion