Announcement

Collapse
No announcement yet.

JPA-Problem - SingleTable-Inheritance

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • JPA-Problem - SingleTable-Inheritance

    Hallo!

    Ich habe ein JPA-Problem mit mehreren one-to-many-Beziehungen. Es geht dabei um folgendes Szenario:

    Wir haben einen Garten. In diesem Garten gibt es mehrere Pflanzen, z.B. Blumen und Bäume. Blumen und Bäume leiten von der gemeinsamen Basisklasse Pflanzen ab. Sowohl Blumen als auch Bäume eines Gartens können abgefragt werden. (Ja ja... ich bin auch kein wirklicher Pflanzen-Fan, jedoch habe ich dieses Beispiel aus einem Buch, welches bei mir einfach nicht funktioniert!)

    Meine Lösung schaut momentan so aus:

    Die Entitäten sehen (grob) folgendermaßen aus:

    @Entity
    @Table(name = "GARDEN_TABLE")
    GardenEntity {
    @Id
    public Long id;

    @Column(nullable = false)
    public String name;

    @OneToMany(mappedBy = "garden", cascade = CascadeType.ALL)
    public List<TreeEntity> trees = new ArrayList<TreeEntity>();

    @OneToMany(mappedBy = "garden", cascade = CascadeType.ALL)
    public List<FlowerEntity> flowers = new ArrayList<FlowerEntity>();

    public GardenEntity(String name) {
    this.name = name();
    }
    }

    @Entity
    @Table(name = "PLANT_TABLE")
    @DiscriminatorColumn(name = "DTYPE", discriminatorType = DiscriminatorType.STRING)
    @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
    PlantEntity {
    @Id
    public Long id;

    @Column(nullable = false)
    public String name;

    @ManyToOne
    @JoinColumn(name = "GARDEN_FK", nullable = false)
    public GardenEntity garden; // important: backref to containing garden

    public PlantEntity(String name, GardenEntity garden) {
    this.name = name;
    this.garden = garden;
    }
    }

    @Entity
    @DiscriminatorValue(value = "FLOWER")
    FlowerEntity extends PlantEntity {
    public String color;

    public FlowerEntity(String name, GardenEntity garden) {
    super(name, garden);
    }
    }

    @Entity
    @DiscriminatorValue(value = "TREE")
    TreeEntity extends PlantEntity {
    public boolean fruits;

    public TreeEntity(String name, GardenEntity garden) {
    super(name, garden);
    }
    }

    Wichtig ist die Backref von Pflanze zu Garten, wir haben also eine birektionale Beziehung.

    Die Tabellen werden folgendermaßen erstellt:

    --Drop Table GARDEN_TABLE;
    Create Table GARDEN_TABLE(
    ID BIGINT NOT NULL,
    NAME VARCHAR(8000),
    primary key (ID))
    ;

    --Drop Table PLANT_TABLE;
    Create Table PLANT_TABLE(
    ID BIGINT NOT NULL,
    GARDEN_FK BIGINT NOT NULL,
    DTYPE VARCHAR(32) NOT NULL,
    NAME VARCHAR(8000),
    COLOR VARCHAR(8000),
    FRUITS SMALLINT,
    primary key (ID))
    ;

    -- constraint between PlantEntity.garden and GardenEntity
    --alter table PLANT_TABLE drop constraint PLANT_TABLE_C01;
    alter table PLANT_TABLE
    add constraint PLANT_TABLE_C01
    foreign key (GARDEN_FK)
    references GARDEN_TABLE (ID)
    On Delete Restrict
    On Update No Action
    ;


    -- index for foreign key attribute PlantEntity.garden
    create Index PLANT_TABLE_F1
    on PLANT_TABLE
    (GARDEN_FK)
    ;


    Das Problem äußert sich Folgendermaßen:
    Wenn ich das ganze ausprobiere, scheint alles schön zu funktionieren. Folgender Use-Case schlägt jedoch fehl:
    1.) Lade einen Garten, der bereits Blumen und Bäume hat -> OK
    2.) Greife auf die Blumen zu -> NOK: In der Collection der Blumen sind auch die Bäume enthalten!


    Kann mir irgendjemand weiterhelfen??


    Vielen Dank
    dubdidub
    Zuletzt editiert von dubdidub; 24.12.2012, 13:23. Reason: Missverständliche Darstellung angepasst: "+ fruits : boolean" -> "public boolean fruits".; Konstruktoren hinzugefügt.

  • #2
    Was ist das für eine Notation?
    + fruits : boolean
    Jedenfalls würde für eine bidirketionale Beziehung die Notation manytoone fehlen
    Wie greifst du auf die Onject zu, wie legst du diesen an?
    Zuletzt editiert von Christian Marquardt; 20.12.2012, 14:02.
    Christian

    Comment


    • #3
      Hi!
      Ich habe die Annotation nun angepasst... ich hoffe sie ist nun verständlicher!?

      Ich weiß nicht, ob ich deine Frage richtig verstehe. Ich hole mir die Objekte über den EntityManager, persistiere sie auch über diesen. Auf die Attribute greife ich über einfache Objektnavigation zu, z.B.:

      // Transaktion A: Lege einen Garden mit einem Baum und einer Blume an
      GardenEntity garden = new GardenEntity("a garden");

      TreeEntity tree = new Tree("a tree", garden);
      garden.getTrees().add(tree);

      FlowerEntity flower = new Flower("a flower", garden);
      garden.getFlowers().add(flower);

      this.getEntityManager().persist(garden);


      VG dubdidub

      Comment


      • #4
        D.h. ein folgendes

        garden.getFlowers()

        enthält den Baum und die Pflanze?

        Kann jetzt da nichts ungewöhnliches sehen. Das müsste ich selbst nachstellen
        Christian

        Comment


        • #5
          Dein unterer Code passt nicht zu dem obigen Code -> Klassennamen?

          Mit folgenden Änderungen läuft es hier u.a. je Subclass eigene Refernz auf garden

          [highlight=java]
          @Entity
          @Table(name = "GARDEN_TABLE")
          public class GardenEntity implements Serializable
          {
          @Id
          @GeneratedValue(strategy = GenerationType.IDENTITY)
          private Long id;
          @Column(nullable = false)
          private String name;
          @OneToMany(mappedBy = "garden",cascade = CascadeType.ALL)
          public List<TreeEntity> trees=new ArrayList<>();
          @OneToMany(mappedBy = "garden",cascade = CascadeType.ALL)
          public List<FlowerEntity> flowers=new ArrayList<>();

          public GardenEntity()
          {
          }

          public GardenEntity(String name)
          {
          this.name=name;
          }

          public Long getId()
          {
          return id;
          }

          public void setId(Long id)
          {
          this.id=id;
          }

          public String getName()
          {
          return name;
          }

          public void setName(String name)
          {
          this.name=name;
          }

          public List<TreeEntity> getTrees()
          {
          return trees;
          }

          public void setTrees(List<TreeEntity> trees)
          {
          this.trees=trees;
          }

          public List<FlowerEntity> getFlowers()
          {
          return flowers;
          }

          public void setFlowers(List<FlowerEntity> flowers)
          {
          this.flowers=flowers;
          }

          }

          [/highlight]

          [highlight=java]@Entity
          @Table(name = "PLANT_TABLE")
          @DiscriminatorColumn(name = "DTYPE",discriminatorType = DiscriminatorType.STRING)
          @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
          public class PlantEntity implements Serializable
          {
          @Id
          @GeneratedValue(strategy = GenerationType.IDENTITY)
          private Long id;
          @Column(nullable = false)
          private String name;

          public PlantEntity()
          {
          }

          public PlantEntity(String name)
          {
          this.name=name;

          }

          public Long getId()
          {
          return id;
          }

          public void setId(Long id)
          {
          this.id=id;
          }

          public String getName()
          {
          return name;
          }

          public void setName(String name)
          {
          this.name=name;
          }

          }

          [/highlight]


          [highlight=java]
          @Entity
          @DiscriminatorValue(value = "FLOWER")
          public class FlowerEntity extends PlantEntity
          {
          private String color;
          @ManyToOne
          @JoinColumn(name = "GARDEN_FK",nullable = false)
          public GardenEntity garden; // important: backref to containing garden

          public FlowerEntity()
          {
          }

          public FlowerEntity(String name,GardenEntity garden)
          {
          super(name);
          this.garden=garden;
          }

          public String getColor()
          {
          return color;
          }

          public void setColor(String color)
          {
          this.color=color;
          }

          public GardenEntity getGarden()
          {
          return garden;
          }

          public void setGarden(GardenEntity garden)
          {
          this.garden=garden;
          }

          }

          [/highlight]


          [highlight=java] @Entity
          @DiscriminatorValue(value = "TREE")
          public class TreeEntity extends PlantEntity
          {
          private boolean fruits;
          @ManyToOne
          @JoinColumn(name = "GARDEN_FK",nullable = false)
          public GardenEntity garden; // important: backref to containing garden

          public TreeEntity()
          {
          }

          public TreeEntity(String name,GardenEntity garden)
          {
          super(name);
          this.garden=garden;
          }

          public boolean isFruits()
          {
          return fruits;
          }

          public void setFruits(boolean fruits)
          {
          this.fruits=fruits;
          }

          public GardenEntity getGarden()
          {
          return garden;
          }

          public void setGarden(GardenEntity garden)
          {
          this.garden=garden;
          }

          }

          [/highlight]
          Christian

          Comment

          Working...
          X