Laden...

NHibernate & abstraktes Klassenmapping-Problem

Erstellt von Michbeck1983 vor 14 Jahren Letzter Beitrag vor 14 Jahren 2.355 Views
Michbeck1983 Themenstarter:in
239 Beiträge seit 2008
vor 14 Jahren
NHibernate & abstraktes Klassenmapping-Problem

verwendetes Datenbanksystem: MS Sql Server 2005 + NHibernate 2.0

Hallo zusammen,

ich stehe hier gerade vor einem Mapping-Problem mit NHibernate. Ich habe eine abstrakte Basisklasse "AJob". Davon abgeleitet sind zwei konkrete Klassen "Task" und "Ticket". Alle drei befinden sich in eigenen Tabellen, die Tabellen "Task" und "Ticket" verweisen dabei über eine Fremdschlüsselbeziehung auf die Tabelle "Job".

Die konkreten Klassen "Task" und "Ticket" sind in der Mapping-Datei für die abstrakte Klasse "AJob" (=> Tabelle "Job") als Joines Subclasses realisiert:


<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping namespace="Core.Domain" assembly="Core" xmlns="urn:nhibernate-mapping-2.2">
  <class name="AJob" table="Job" lazy="false">
    <id name="Id" column="Id" type="Guid">
      <generator class="assigned" />
    </id>

    <!-- Normale Properties ... -->

    <joined-subclass name="Ticket" table="Ticket">
      <key column="Job" />
      <!-- Properties der konkreten Klasse -->
    </joined-subclass>

    <joined-subclass name="Task" table="Task">
      <key column="Job" />
      <!-- Properties der konkreten Klasse -->
    </joined-subclass>

  </class>
</hibernate-mapping>

Jetzt habe ich in einer weiteren gemappten Klasse eben eine Spalte, die entweder auf "Task" oder "Ticket" verweist, also einer der konkreten Klassen. Das Problem das ich habe ist, dass ich nicht weiß wie ich das Mapping realisieren soll - wenn ich ein many-to-one-Mapping benutze auf die Klasse AJob, bekomme ich (logischerweise) die Fehlermeldung, dass er die abstrakte Klasse nicht instantiieren kann.

Zwischenzeitlich habe ich etwas über den Diskriminator gelesen, der mein Problem aber nicht löst (so glaube ich das zumindest), da die ID's von "Task" und "Ticket" nicht fest sind und ich deswegen keinen discriminator-value benutzen kann. Oder täusche ich mich da?

Hat irgendjemand eine Idee oder einen Wink, wie ich dieses Problem lösen könnte?

Gruß Michbeck1983

Neulich im Computerkurs:
Mein Computer kennt Else nicht! 😁


[URL]XING-Profil[/URL]

M
90 Beiträge seit 2009
vor 14 Jahren

Hallo,

Ich bin mir nicht 100% sicher, aber es wäre möglich, dass es daran liegt, dass du nicht explizit beim Mapping der abstrakten Basisklasse angibst, dass sie auch abstrakt ist. (Attribute abstract="true").

Das liegt denk ich daran, dass Hibernate ursprünglich nur auf die XML Mapping Daten "hört" und der abstract-Modifizierer der Klasse selbst nicht beachtet wird. Demnach versucht Hibernate immer die höchste instanzierbare Klasse zu verwenden.

Und gleich ein Hinweis: Darin liegt auch für später der Fallstrick; man kann sich nicht darauf verlassen, das Hibernate wirklich den konkreten Typ instanziert, sprich "is" und "as" sind nutzlos, man muss dann per Session.Load<ConcreteType>(object.<KeyProperty>) sicherstellen, dass der konkrete Typ frisch geladen wird.

Gruß
Joe

EDIT:
Discriminator brauchst du bei der Joined-Subclass-Variante definitiv nicht.

Michbeck1983 Themenstarter:in
239 Beiträge seit 2008
vor 14 Jahren

Hallo madjoe,

erstmal danke für deine Antwort. Ich war im Urlaub, drum antworte ich erst jetzt.

Das ich den Discriminator nicht brauche, habe ich mittlerweile auch herausgefunden. Ich habe meine Mapping-Datei nach deinem Tipp "umgebaut" und das abstract-Tag hinzugefügt.

Das Hauptproblem besteht damit leider weiterhin: wie schreibe ich in einer Mapping-Datei, dass die betroffene Spalte entweder ein Ticket oder ein Task, also einer der konkreten Implementierungen meiner abstrakten Klasse, sein kann? Klar, wenn ich auf meine abstrakte Klasse verweise, versucht NHibernate diese zu instanziieren, was fehlschlägt.

Gruß Michbeck1983

Neulich im Computerkurs:
Mein Computer kennt Else nicht! 😁


[URL]XING-Profil[/URL]

R
103 Beiträge seit 2009
vor 14 Jahren

Hallo,

schau mal in der Hibernate Referenz doku unter

8.1.6. Table per concrete class, using implicit polymorphism

nach. Da gibt es ein Beispiel wie man so etwas macht. In dem Beispiel wir mit dem <any> mapping gearbeitet. Bin auch gerade dabei so etwas zu modellieren..

M
90 Beiträge seit 2009
vor 14 Jahren

Hallo,

Hab den Thread jetzt leider auch nicht mehr verfolgt.
Ja so eine Idee, das mit Interfaces umzusetzen kam mir auch schon. Schade ist dabei nur, dass man keine direkte Erweiterung der Werte erreicht bzw. bei NHibernate leider sowieso stets das ursprüngliche Mapping-File ändern muss, möchte man seinen Funktionsumfang erweitern.

@Michbeck1983
Direkt wirst du das mit NHibernate leider sowieso nicht erreichen, da bei dieser Methode nie der richtige konkrete Typ geladen wird.

Aber ich verstehe dein Problem, mir gings genauso, einer "richtige Ableitung" gibt man hier natürlich gerne den Vorzug, gerade wenn man schnell ein paar native Filter und Order By Klauseln anwenden möchte - und weil man es so gewohnt ist, und zu guter Letzt, weil natürlich stets das gehen soll, was die Sprache sonst auch kann, abgesehen davon ob es gutes oder schlechtes Design ist.

Aber so wie ich die Sache sehe, muss man hier einfach die gemeinsamen Attribute in eine Container-Klasse packen und die spezifischen Teile als Komponente im Container speichern - Die Komponenten implementieren dann alle das gleiche Interface (welches ja keine Tabelle braucht) und schon hat man den gewünschten Effekt.

Gruß
Joe

R
103 Beiträge seit 2009
vor 14 Jahren

@madjoe

Umm, ging mir bei meinem vorigen Kommentar weniger um die direkte Implementierung in der Hibernate Doku mittels Interfaces, sondern um das <any> Attribut, mit dem sich eine Verlinkung zu beiden abgeleiteten Klassen mittels einer <any> Property machen lässt.