Ich arbeite mich gerade in OXID ein und möchte einen CSV Import für Kategorien programmieren. Ich wundere mich die ganze Zeit, warum fast alle Primary IDs in der Datenbank nicht autoincrementiert werden sondern aus einer recht wirren Zeichenfolge bestehen. Weiß jemand den Grund dafür?
Das Ganze trifft auch die OXIDPARENTID in der Tabelle “oxcategories”. Ich weiß jetzt nicht, ob ich mit den Ids aus meiner CSV Datei arbeiten kann (1,2,3,4,5… n) oder alles in HEX Hashes a la “8a142c3e4143562a5.46426637” wandeln muß.
[QUOTE=bjbro-clgn;29503]Ich arbeite mich gerade in OXID ein und möchte einen CSV Import für Kategorien programmieren. Ich wundere mich die ganze Zeit, warum fast alle Primary IDs in der Datenbank nicht autoincrementiert werden sondern aus einer recht wirren Zeichenfolge bestehen. Weiß jemand den Grund dafür?
Das Ganze trifft auch die OXIDPARENTID in der Tabelle “oxcategories”. Ich weiß jetzt nicht, ob ich mit den Ids aus meiner CSV Datei arbeiten kann (1,2,3,4,5… n) oder alles in HEX Hashes a la “8a142c3e4143562a5.46426637” wandeln muß. [/QUOTE]
Die IDs können auch aus “normalen” Werten bestehen!
Das liegt hauptsächlich daran, dass alle Entities von oxBase o.Ä. erben und im Model auch m:n-Relationen vorgesehen sind, welche verschiedene Entity-Typen auf eine Relation abbilden. Man will sicherstellen, dass es keine Entities gibt, die eine gleiche ID haben, aber unterschiedliche Identitäten haben. Insofern tut man sehr (!) gut daran, sich an die Konvention zu halten. Beim Import von Daten kannst Du folgendermaßen vorgehen:
Pro Import-Zeile ermittle eine eideutige Eigenschaft (Artikel-Nummer z.B.)
Konkateniere den Namen der entity, z.B. oxarticle mit dieser Eigenschaft
Erstelle einen MD5-Hash und nimm diesen als oxid
Das ganze hat zwei Vorteile: Zum einen ist es somit sehr, sehr, sehr unwahrscheinlich, dass eine oxid mehrmals vorkommt und Du hast eine determinischte Methode, die ID im Shop zu ermitteln, was sehr nützlich bei späteren Datenabgleichen sein kann. Ein Lookup entfällt, da die oxid by convention ermittelt wird.
[QUOTE=PCO;29520]Das liegt hauptsächlich daran, dass alle Entities von oxBase o.Ä. erben und im Model auch m:n-Relationen vorgesehen sind, welche verschiedene Entity-Typen auf eine Relation abbilden. Man will sicherstellen, dass es keine Entities gibt, die eine gleiche ID haben, aber unterschiedliche Identitäten haben.[/QUOTE]
Das könnte man ja auch über ein “auto increment” erreichen…
Nein, kann man nicht, denn autoincrement bezieht sich auf eine Tabelle. Es fängt für jede Tabelle wieder bei 1 an. Wenn Du nun z.B. in oxobject2discount einmal eine Warengruppe und einmal einen Kunden hinzufügen willst, dann könnte es sein, dass beide die gleiche ID haben, z.B 1. Mit der Universal OXID kann das nicht passieren. Die Unterscheidung über TYPE wäre zwar noch möglich, aber drauf ankommen lassen würde ich es nicht. Mit Autoincrement holt man sich auf jeden Fall leicht Dubletten, die eigentlich nicht vorgesehen sind.
[QUOTE=PCO;29533]Nein, kann man nicht, denn autoincrement bezieht sich auf eine Tabelle. Es fängt für jede Tabelle wieder bei 1 an. Wenn Du nun z.B. in oxobject2discount einmal eine Warengruppe und einmal einen Kunden hinzufügen willst, dann könnte es sein, dass beide die gleiche ID haben, z.B 1. Mit der Universal OXID kann das nicht passieren. Die Unterscheidung über TYPE wäre zwar noch möglich, aber drauf ankommen lassen würde ich es nicht. Mit Autoincrement holt man sich auf jeden Fall leicht Dubletten, die eigentlich nicht vorgesehen sind.[/QUOTE]
Da hast Du allerdings recht…
Vielen Dank für die Antworten. Ist ein interessantes System.
Dadurch resultierte bei mir noch das Problem, das ich die Kategorien per CSV natürlich auch updaten will. Dummerweise habe ich dann in der CSV Datei natürlich andere Ids, als die, die von OXID vergeben werden. Das ist schlecht fürs Update.
Konnte ich aber auch elegant lösen, indem ich in der categories Tabelle einfach ein zusätzliches Feld für die CSV Id erweitert habe. Das OXID Objektmodell ist da ja sehr grosszügig und speichert alles, was per $object->assign($record) eingebracht wird ja auch ab - wenn das DB Feld existiert. Sehr schön und flexibel.
Wenn Du das ganze über MD5 o.Ä. machst, dann brauchst Du keine Extra-Spalten. Wie gesagt, MD5 ist deterministisch, Du kannst also auch ohne Kenntnis der OXID vor dem Import dann während des Imports die OXID generieren, auf Basis z.B. von der ID in der zu importierenden Liste. Wenn Du noch einen prefix dazu tust, dann ist der Hash auch mit sehr hoher Wahrscheinlichkeit kollisionsfrei mit anderen Entities.
Also wir machen das dann so:
FOREACH Artikel IN ArtikelImportListe
Table.Oxid = MD5("importartikel" + Artikel.Artikelnummer)
END FOREACH
Es ist also möglich, eine eindeutige OXID zu generieren und diese auch schon vor dem Import zu wissen.
Brauchst keinen MD5 achso, und so toll ist das system nicht, hat auch ein paar gravierende nachteile. stichwort fremdschlüssel bzw fremdschlüsselüberprüfung.
Durch den MD5-Ansatz auf Basis von bekannten Informationen + Prefix hast du einen deterministischen (= Vorhersagbaren) Key. oxUtilsObject::getInstance()->generateUID() baut dir eine random UID und genau das will bjbro-clgn ja eben nicht, weil er später mal Updates machen will. Er könnte sich nun den alten Primary-Key aus den Quelldaten mit in die Oxid-DB speichern (extra-Spalte etc. pp) oder halt eine Strategie entwerfen, wie er aus dem Primary Key der Quelldaten eine UID ableiten kann, die eindeutig ist, dafür ist Hashing eine super Methode und bjbro-clgn’s Problem ist gelöst, da er schon an den Quelldaten die OXID fürs Update bestimmten kann, und er hat sich an die Conventions gehalten.
Darum ist das die #1-Lösung für bjbro-clgn mit allen Vorteilen aber ohne Nachteile.
Übrigens würde mich interessieren, wo die OXIDs ein Nachteil bei integeren Foreign-Key-Relations sein sollen? Ich sehe da kein Problem.
Übrigens würde mich interessieren, wo die OXIDs ein Nachteil bei integeren Foreign-Key-Relations sein sollen? Ich sehe da kein Problem.
Gab ja schon ein paar bugs die auf diesem Problem beruhten.
Und es ist ganz einfach: Du kannst keine echten foreign key relations verwenden, zumindest nicht bei den oxobject2something tabellen, da dort ein oxobject ein artikel, eine kategorie oder ein user sein kann. dh, wenn du einen artikel löschst, musst du ihn in allen zuordnungen händisch (bzw der programmierer muss das tun) löschen, anstatt die foreign key funktion von innodb zu nutzen. Zudem geht das ganze auch auf die performance, weil diese indizes viel schneller sind als wenn mysql vorher nicht weiss wo der key hingehört.
ausserdem kann man so in jede dieser tabellen alles eintragen, es wird ja nicht geprüft ob das überhaupt plausibel ist weil keine relationen bzw mehrfachrelationen bestehen.
ansonsten hat man datenleichen noch und nöcher und konsistent ists halt auch nicht.
Das mit den Foreign Keys sollte sich aber trotzdem realisieren lassen. Ich sehe deine Einwände allerdings ein. Im Model wird heftig vererbt und in der Datenbank wird es dann nur über OXTYPE abgesichert. In den meisten Fällen sollten FKs aber kein Problem sein. Nur bei den m:n-Mappings über oxobject, da wirds dann wohl lustig.
Oxid könnte sich ja fürs nächste Release mal anschauen, wie z.B. in marktüblichen (enterprise-tauglichen) Persistence-Units sowas realisiert ist. Hibernate hätte wohl z.B. eine Tabelle OXOBJECT angelegt, über die alle m:n-Relationen gemappt werden. Dazu gibt es dann Spezialisierungs-Tabellen, die sich selbst auf OXOBJECT referenzieren. Schon hast Du Vererbung mit integeren Keys, Cascade etc., spannendes Thema - oder auch nicht, je nach Perspektive
Ich meine hier irgendwo letztens sowieso ne Timebomb-Wanung gelesen zu haben, dass DbObject auch deprecated ist. Wenn ich mir anschaue, wieviel Speicher das Viech frisst (s. mein letztes Posting von wegen Skalierung) wäre es ggf. sowieso angebracht, mal was neues zu suchen, auch wenn PHP hier irgendwie etwas hinterherhinkt im vgl. zu Java (JPA/Hibernate), .NET (Linq/NHibernate) oder Ruby (Rails).
Es bleibt spannend - ich will auch nicht noch philosophischer werden.
Schönes Wochenede!
Die Warnung stammt von mir PHP bietet seit längerem schon eine native Datenbankabstraktionsebene die wesentlich fixer ist als ADOdb: http://de.php.net/PDO
[QUOTE=csimon;29623]Die Warnung stammt von mir PHP bietet seit längerem schon eine native Datenbankabstraktionsebene die wesentlich fixer ist als ADOdb: http://de.php.net/PDO[/QUOTE]
Na dann verstehen wir uns ja Hoffentlich, wird dann auch was daraus, ich bin mal gespannt, wies es weiter geht bei Oxid.
[B]
bjbro-clgn: Ist deine Frage beantwortet? Weißt Du nun, wie Du vorgehen kannst oder gibts noch Fragen?[/B]
@PCO: Meine Frage wurde ausführlich beantwortet. Seit meinem letzten Post, weiß ich, warum die ID so ist und das es besser ist nicht in interne Mechanismen einzugreifen, weils dann halt in irgend einer noch unbekannten Coreklasse bei einem N:M Querybuild knallen kann.
Na dann verstehen wir uns ja Hoffentlich, wird dann auch was daraus, ich bin mal gespannt, wies es weiter geht bei OXID.
naja, zumindest nicht mit ADOdb und dem uralt smarty g ich würd ja schon fast sagen das man in einem möglichen OXID 4.5 einen auf Firefox macht und da schon ADOdb ersetzt und Smarty 3 einführt (was hoffentlich bis dahin mal aus dem betastadium ist)
ich hätte generell lieber ein traditionelles normalisiertes db modell, das ist viel besser zu warten und ich bezweifle das das wenn ordentlich gepflegt mit den aktuellsten techniken sonderlich schlechterere performance liefern würde als das jetzige. Zudem kann man ja auch schnittstellen für bekannte caches etc. schaffen (ich glaub das geht in der EE).