Core Data - Beziehungen

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Core Data - Beziehungen

    Schönen guten Tag,
    ich habe eine Frage bezüglich der Beziehungen in einer Datenbank in Xcode.

    Ich habe eine Datenbank mit folgenden Tabellen und Spalten:

    Bibliothek
    - Name

    Regal
    - Nummer

    Buch
    - Title


    Jetzt kann eine Bibliothek natürlich mehrere Regale haben und ein Regal natürlich mehrere Bücher.

    Daher habe ich folgende Beziehungen eingetragen:

    Bibliothek (One) <---> (Many) Regal (One) <---> (Many) Buch


    Wenn ich mir daraus jetzt die Sub-Klassen erstellen lasse, dann bekomme ich ein (in meinen Augen) falsches Ergebnis.

    Die Klassen haben jetzt folgende Attribute:

    Bibliothek:
    - Name (String)
    - Regal (NSSet)

    Regal:
    - Nummer (NSNumber)
    - Buch (NSSet)
    - Bibliothek (Bibliothek) <--- FALSCH?

    Buch:
    - Title (String)
    - Regal (Regal) <--- FALSCH?


    Ich habe die falschen Stellen markiert.
    Also ich hätte jetzt eigentlich gedacht, dass ich in einem "Bibliothek"-Objekt mehrere "Regal"-Objekte speicher und in einem "Regal"-Objekt mehrere "Buch"-Objekte.
    Und sobald ich das "Bibliothek"-Objekt speicher, werden alle "Regal"-Objekte und alle "Buch"-Objekte automatisch mit gespeichert.

    Muss ich jetzt in einem "Regal"-Obekt das Haupt-"Bibliothek"-Objekt zuweisen?
    MacBook Air Late 2008
    OS X Mountain Lion 10.8.4
  • Knate schrieb:

    Wenn ich mir daraus jetzt die Sub-Klassen erstellen lasse, dann bekomme ich ein (in meinen Augen) falsches Ergebnis.

    Die Klassen haben jetzt folgende Attribute:

    Bibliothek:
    - Name (String)
    - Regal (NSSet)

    Regal:
    - Nummer (NSNumber)
    - Buch (NSSet)
    - Bibliothek (Bibliothek) <--- FALSCH?

    Buch:
    - Title (String)
    - Regal (Regal) <--- FALSCH?
    Das ist vollkommen korrekt, was dir da erstellt wurde. Ein NSSet kann mehrere (many) Regale aufnehmen, während Bibliothek nur auf eine (one) Bibliothek Instanz verweisen kann. Genauso verhält es sich bei der Beziehung Regal-Buch.
  • Recht hat er, der DanielBocksteger95.
    Wobei hier erst einmal nur ein Verständnisproblem mit Entity-Relationship Modellen vorliegt, das ist ja zum Glück von Datenbanken losgelöst.

    Zusammengefasst:
    Du bist der Meinung, dass Deine Beziehungen
    Bibliothek(1):(n)Regal(1):(n)Buch

    Anders dargestellt werden sollen als
    Bibliothek(Sammlung):(Einzelobjekt)Regal(Sammlung):(Einzelobjekt)Buch

    Da liegst Du falsch, das soll ganz genau so aussehen.
    1:n in Beziehung zu Bibliothek:Regal bedeutet ja, eine Bibliothek (Einzelobjekt) besitzt mehrere Regale (Sammlung).
    Entsprechend ist die Rückverzweigung: Ein Regal (Einzelobjekt) steht in ganz genau einer Bibliothek (Einzelobjekt).
    Mir ist zumindest nicht bekannt, wie man ein einziges Regal auf mehrere Gebäude aufteilen kann. Es wäre möglich, dann würde man aber von Regalhälften und Regalteilen sprechen, und auch da stünde ein Regalteil in ganz genau einer Bibliothek.

    Du hast also nicht nur Deine definierten Beziehungen bekommen, sondern auch die dazugehörigen Rückbeziehungen.
    Buch(Einzelobjekt):(Sammlung)Regal(Einzelobjekt):(Sammlung)Bibliothek

    Die Darstellung im Code geht immer vom betreffenden Objekt aus, nicht von dem, was Du Dir in der Relationship gedacht hast.
    Deine Regal(1):Buch(N) Beziehung ist nur aus Sicht des Regals 1:n.
    Aus Sicht des Buches ist es eine 1:1 Beziehung.
    Wäre dem anders, hättest Du eine n:m Beziehung: 1 Regal kann n Bücher haben. Ein Buch kann in n Regalen stehen.

    (Klingt blöd, wenn man von der materiellen Realität ausgeht. Ein konkretes Buch kann nur in einem konkreten Regal stehen. Wird das Buch aber nicht einzeln identifizierbar gemacht, sondern nur an Hand seiner ISBN gepflegt, kannst Du in der Datenbank theoretisch 5x das Buch mit der ISBN 978-3-8362-1463-6 in Deiner Bibliothek haben und auf fünf unterschiedliche Regale verteilen.)

    Vielleicht kann man das Ganze auch so verdeutlichen:
    Bibliothekt(1:n):(1:1)Regal(1:n):(1:1)Buch

    --

    Wozu das Ganze?

    Im Unterschied zu einer Datenbank, in der Du eine bestimmte Bibliothek an Hand eines Buches suchst, indem Du die ID des Buches holst, die ID des Regals holst, das die ID des Buches hat und Dir anschließend die ID der Bibliothek holst, die die ID des Regals hat, hangelst Du Dich im Objektgraphen dank der Rückbeziehung einfach nach oben.
    Also statt einem umständlichen

    SQL-Abfrage

    1. SELECT buch.id FROM buch WHERE …;
    2. SELECT regal.id FROM regal WHERE buchID = buch.id;
    3. SELECT * FROM bibliothek WHERE regalID = regal.id;

    Ein beherztes

    C-Quellcode

    1. id bibliothek = [[meinBuch regal] bibliothek];

    Soviel zu den Grundlagen.
    Um Deine Frage zu beantworten: Jain.

    Ja, weil Du natürlich die Rückreferenz gemäß Deines ERM Entwurfes setzen musst.
    Nein, weil Core Data mit dem Hinzufügen eines Objektes die Sache für Dich übernimmt.
    In beide Richtungen. Fügst Du einer leeren Bibliothek ein Regal hinzu, wird dem Regal die Referenz auf die Bibliothek gesetzt. Setzt Du ein frei stehendes Regal in eine Bibliothek, dann wird es auch deren Regalsammlung hinzugefügt.

    Zusammengefasst ist Dein Verständnisproblem die gratis hinzugefügte Rückbeziehung, die bei Objektgraphen notwendig, bei relationalen Datenbanksystem jedoch hinderlich ist.
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P

    Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von Marco Feltmann ()

  • Korrekt. Implementierungsdetail.
    Es ist nicht unbedingt sinnvoll, ein solches Datenmodell zu wählen, das lediglich besagt:

    Quellcode

    1. {
    2. "ISBN": "978-3-8362-1463-6",
    3. "Anzahl": 5,
    4. "Regale":
    5. [
    6. {
    7. "Nummer": 5,
    8. "Anzahl": 2,
    9. },
    10. {
    11. "Nummer": 23,
    12. "Anzahl": 1
    13. },
    14. {
    15. "Nummer": 42,
    16. "Anzahl":2
    17. }
    18. ]
    19. }
    Alles anzeigen
    Es ist dennoch möglich.
    Und ich bin mir sicher, Du hast schon etliche historisch gewachsene Software gesehen, der ähnlich… unverständliche Datenmodelle verwendet hat. ;)
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P
  • Erst einmal vielen Dank für die Antworten.
    Ich denke, das habe ich soweit verstanden.

    Mein Annahme rührt von folgendem Gedanken her:
    Ich dachte, ich erstelle ein "Bibliothek"-Objekt, in diesem füge ich dann mehrere "Regal"-Objekte hinzu wobei jedes "Regal"-Objekt wi(e)derum mehrere "Buch"-Objekte hat.
    Jetzt bräuchte ich nur das "Bibliothek"-Objekt speichern und der Compiler dröselt die anderen Objekte selbstständig auf und speichert diese selbstständig.


    Wie ich es aber jetzt verstanden habe, muss ich jedes "Regal"-Objekt einzeln speichern, wobei ich in jedem dieser Objekt das "Bibliothek"-Objekt setzte, damit die Regale in Beziehung mit der Bibliothek stehen.

    Beispiel:
    1 x Bibliothek
    3 x Regal
    2 x Buch

    Ich erzeuge ein "Bibliothek"-Objekt, setzte den Namen und speichere das Objekt ab.
    Da ich zu diesem Zeitpunkt keine Regale habe und Regal in der Bibliothek-Klasse eh vom Typ NSSet ist (und man daher sowieso keine Werte setzten kann), bleibt es leer.

    Dann erstelle ich ein Regal-Objekt, weise diesem Objekt das Bibliothek-Objekt zu und speichere dann das Regal-Objekt in der Datenbank.
    Und das mit einer For-Schleife noch 2 weitere Male.

    Und das selbe Spiel mit den Büchern.
    Wäre das so richtig?

    Ich habe also nicht nur einen einzigen "großen" Insert, sondern für jeden Objekt einen einzelnen.
    MacBook Air Late 2008
    OS X Mountain Lion 10.8.4
  • Du hast überhaupt keinen Insert.

    Gewöhn Dich daran, dass Du die ganze Zeit nur und ausschließlich mit Objekten arbeitest.

    Inwieweit die Objekte hinter den Beziehungen gespeichert werden, hängt ausschließlich davon ab, wann Du Deine Objekte speicherst.

    Legst Du die Bibliothek an und speicherst sie, wird nur die Bibliothek gespeichert.

    Legst Du die eine Biblitothek mi vier Regalen und einhundertfünfunddreißig Büchern an und speicherst sie, wird der gesamte Objektgraph gespeichert.

    Interessant ist hier nur, was Du unter 'speichern' und 'Schleifen' verstehst.
    Wie gedenkst Du denn, die Objekte zu speichern? :evil:
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P
  • Amin Negm-Awad schrieb:

    Das ist dann kein Buch, sondern ein Titel.
    Es ist ja auch kein Inventar, sondern eine Standortliste.
    Ähnlich wie bei diesen CarSharing/Taxi Apps: Ein Fahrzeug findest Du dort, dort, dort, dort und dort.
    Dieses eine (reservierte? via Kennzeichen spezifizierte? gebuchte? beschädigte? leergefahrene?) Fahrzeug findest Du dort.
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von Marco Feltmann ()

  • Ok, ich habe mich missverständlich ausgedrückt.
    Die Fachbegriffe sollte ich lernen zu benutzen.

    Mit "Insert" war natürlich kein plain SQL insert gemeint, sondern natürlich die Save-Methode von ManagedObjectContext.

    Das der komplette Objektgraph gespeichert wird, ist ja fabelhaft. So lobe ich mir das.


    Dann habe ich zu diesem Thema aber noch eine Frage.
    Wenn ich mir jetzt ein Bibliothek-Objekt erstelle, dann leite ich dieses doch von der Bibliothek Subklasse ab, die mir aus meinem ERD erstellt wurde, oder?
    Wenn ja, dann verstehe ich noch nicht, wie ich diesem Objekt dann mehrere Regal-Objekte zuweisen kann, da Regal ja vom Typ NSSet ist, und (wenn ich das richtig gelesen habe) NSSet inmutable ist, also man keine Daten hinzufügen kann.

    Wie mache ich das denn dann?
    MacBook Air Late 2008
    OS X Mountain Lion 10.8.4
  • Knate schrieb:

    Dann habe ich zu diesem Thema aber noch eine Frage.
    Wenn ich mir jetzt ein Bibliothek-Objekt erstelle, dann leite ich dieses doch von der Bibliothek Subklasse ab, die mir aus meinem ERD erstellt wurde, oder?
    Du erzeugst eine Instanz der Klasse Bibliothek. Zum Beispiel so:
    var bibliothek = NSEntityDescription.insertNewObjectForEntityForName("Bibliothek", inManagedObjectContext:<hier dein ManagedObjectContext einsetzen>)

    Knate schrieb:

    Wenn ja, dann verstehe ich noch nicht, wie ich diesem Objekt dann mehrere Regal-Objekte zuweisen kann, da Regal ja vom Typ NSSet ist, und (wenn ich das richtig gelesen habe) NSSet inmutable ist, also man keine Daten hinzufügen kann.
    Du erzeugst eine Instanz der Klasse Regal:
    var regal = NSEntityDescription.insertNewObjectForEntityForName("Regal", inManagedObjectContext:<hier dein ManagedObjectContext einsetzen>)

    Bibliothek setzen:
    regal.bibliothek = bibliothek
    Durch die gesetzte inverse relationship, fügt Core Data das Regal in das NSSet der Bibliothek Instanz ein. Core Data Magic halt.

    Quellcode

    1. if bibliothek.regal.containsObject(regal) == true {
    2. print("Das Regal wurde hinzugefügt")
    3. }
  • Ok, das sind wirklich hilfreiche Antworten.
    Damit kann ich wirklich arbeiten ^^


    Jetzt gibt es nur noch ein Problem.
    Meine Regal-Objekte erzeuge ich in einem anderen ViewController als die Bibliothek-Objekte.

    Ich "muss" also mein Bibliothek-Objekt via Seque an den anderen ViewController übergeben.
    Normalerweise kein Problem, aber ich bekomme einen Fehler:

    Failed to call designated initializer on NSManagedObject class 'Bibliothek'


    Denn bei der Variablen, die ich wie folgt erstelle, handelt es sich um ein NSManagedObject-Objekt, und nicht um ein Bibliothek-Objekt.

    Quellcode

    1. var bibliothek = NSEntityDescription.insertNewObjectForEntityForName("Bibliothek", inManagedObjectContext:context)
    Demnach dürfte die Zuweisung


    Quellcode

    1. regal.bibliothek = bibliothek
    auch nicht funktionieren, da die Klasse "Regal" ein Bibliothek-Objekt möchte und kein NSManagedObject-Objekt.

    Das Casten mit bibliothek as! Bibliothek funktioniert auch nicht.

    Da stehe ich noch gerade etwas auf dem Schlauch.
    MacBook Air Late 2008
    OS X Mountain Lion 10.8.4
  • Marco Feltmann schrieb:

    Amin Negm-Awad schrieb:

    Das ist dann kein Buch, sondern ein Titel.
    Es ist ja auch kein Inventar, sondern eine Standortliste.Ähnlich wie bei diesen CarSharing/Taxi Apps: Ein Fahrzeug findest Du dort, dort, dort, dort und dort.
    Dieses eine (reservierte? via Kennzeichen spezifizierte? gebuchte? beschädigte? leergefahrene?) Fahrzeug findest Du dort.
    Eben. Deshalb hat das Buch auch stets nur ein Regal.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Willkommen in der Welt von Swift. =)

    Hat der Amin Negm–Awad nicht mal gefrotzelt, dass so etwas wie Core Data mit Swift nicht zu realisieren ist?

    Egal, an diesem Punkt bin ich raus, da Objective–C das genau so macht wie Du es erwarten würdest und ich Swift in Verbindung mit Cocoa stumpf nicht benutze.
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P
  • Amin Negm-Awad schrieb:

    Das bracht für die Benutzung ja schon ein eigenes Schlüsselwort.
    Ja und dieses Schlüsselwort muss man dann auch in Core Animation für die Implementierung eigener Property-Animationen in CALayer-Subklassen verwenden. Das sieht dann richtig Klasse aus:

    Java-Quellcode

    1. class KochCurveLayer: CALayer {
    2. @NSManaged var depth: CGFloat
    3. ...
    4. }
    Da weiss der Leser sofort Bescheid. ;)
    „Meine Komplikation hatte eine Komplikation.“
  • macmoonshine schrieb:

    Amin Negm-Awad schrieb:

    Das bracht für die Benutzung ja schon ein eigenes Schlüsselwort.
    Ja und dieses Schlüsselwort muss man dann auch in Core Animation für die Implementierung eigener Property-Animationen in CALayer-Subklassen verwenden. Das sieht dann richtig Klasse aus:

    Java-Quellcode

    1. class KochCurveLayer: CALayer {
    2. @NSManaged var depth: CGFloat
    3. ...
    4. }
    Da weiss der Leser sofort Bescheid. ;)
    Na, ja, halt alles was dynamisch ist. Den fiel als erstes bloß Core Data ein, wie es aussieht. Man hätte halt ein aussagekräftigeres Schlüsselwort wählen sollen. Vielleicht

    Quellcode

    1. @FlexibilityAdditionForLanguageTooInflexibleToAllowDynamicBindindButFlexbleEnoughForHavingAKackwurstOperator var depth: CGFloat


    Jeder hätte sofort gewusst, was Sache ist. Wollte man mutmaßlich nicht.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?