jpa annotation

Dieses Thema jpa annotation im Forum "Application Tier" wurde erstellt von musium, 6. Apr. 2012.

Thema: jpa annotation Hallo zusammen (Ich arbeite mit JBoss 6, MySql 5.5.2 und spreche hibernate über javax.persistence.* an.) Ich bin...

  1. Hallo zusammen

    (Ich arbeite mit JBoss 6, MySql 5.5.2 und spreche hibernate über javax.persistence.* an.)
    Ich bin das erste mal am JPA ausprobieren und steh schon voll auf dem Schlauch :(
    Ich versuche gerade eine kleine Test Applikation zu schreiben (mini Zeitverwaltung).

    Meine Enteties sehen wie folgt aus:

    Code (Java):

    @Entity
    @Table(name = "TimeEntry")
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class TimeEntry implements Serializable
    {
        @Id
        @GeneratedValue
        private Long id;
        private String doneWork;
        private Date beginTime;
        private Date endTime;
    }
    Code (Java):

    @Entity
    @Table(name = "Project")
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Project implements Serializable
    {
        @Id
        @GeneratedValue
        private Long id;
        //@ManyToOne(targetEntity = TimeEntry.class) was muss hier hin?
        private List<TimeEntry> entries;
        private String name;
        private String description;
    }
    Nun die erste Frage, was muss ich für eine Beziehung setzten für Project.entries?
    (Ein TimeEntry sollte einem Project zugeteilt werden können und ein Project sollte n TimeEntry haben können)
    .....
    Weiter habe ich in meiner Applikation noch ein jaas login mit einer MySQL Datenbank dahinter.
    (Tabellen: user & roles)
    Ein TimeEntry sollte nicht nur einem Projekt sondern auch einem User zugeteilt werden. Als user würde ich gerne den Eintrag in der user Tabelle (welche auch für das Login gebraucht wird) benutzen... geht das und wenn ja, muss ich etwas spezielles beachten?

    Hier noch ein ERM, wie ich mir die Datenbank ungefähr vorstelle.
    [​IMG]

    persistence.xml
    [XML]
    <?xml version="1.0" encoding="UTF-8"?>
    <persistence xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
    version="2.0">
    <persistence-unit name="persistenceCotext/jTime">
    <jta-data-source>java:jdbc/jTime</jta-data-source>
    <properties>
    <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
    <property name="hibernate.hbm2ddl.auto" value="create-drop" />
    <property name="hibernate.show_sql" value="true" />
    <property name="hibernate.format_sql" value="true" />
    </properties>
    </persistence-unit>
    </persistence>
    [/XML]

    mysql-ds.xml
    [XML]
    <local-tx-datasource>
    <jndi-name>jdbc/jTime</jndi-name>
    <connection-url>jdbc:mysql://localhost:3306/jtime</connection-url>
    <driver-class>com.mysql.jdbc.Driver</driver-class>
    <user-name>root</user-name>
    <password></password>
    <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
    <metadata>
    <type-mapping>mySQL</type-mapping>
    </metadata>
    </local-tx-datasource>
    [/XML]

    login-config.xml
    [XML]
    <application-policy name="jTimeSecurityDomain">
    <authentication>
    <login-module code="org.jboss.security.auth.spi.DatabaseServerLoginModule" flag="required">
    <module-option name="unauthenticatedIdentity">guest</module-option>
    <module-option name="dsJndiName">java:jdbc/jTime</module-option>
    <module-option name="principalsQuery">SELECT password FROM user WHERE username=?</module-option>
    <module-option name="rolesQuery">SELECT role, 'Roles' FROM roles WHERE username=?</module-option>
    </login-module>
    </authentication>
    </application-policy>

    [/XML]
     
  2. Vielleicht hilft dir das Grundlagen Training weiter --> *Klick*
  3. Bin nun etwas weiter und hab eine Lösung die funktioniert.
    Wäre aber super, wenn mir jemand ein kleines Feedback zu meiner Implementierung geben könnte, den ich hab keine Ahnung ob, dass was ich geschrieben habe, andere Gefahren mit sich bringen könnte.

    Hier meine Klassen:


    Code (Java):

    @Entity
    @Table(name = "Project")
    @NamedQueries
    ({
        @NamedQuery(name = "Project.findAll", query = "from Project p"),
        @NamedQuery(name = "Project.findByName", query = "from Project p where p.name = :name")
    })
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Project implements Serializable
    {
        @Id
        @GeneratedValue(strategy=GenerationType.AUTO)
        private Long id;
        @OneToMany(targetEntity=TimeEntry.class,mappedBy="project", cascade={CascadeType.ALL} ,orphanRemoval=true)
        private List<TimeEntry> entries;
        @Column (unique=true)
        @Basic(optional=false)
        private String name;
        private String description;
       
        public Project(String name, String description)
        {
            this.name = name;
            this.description = description;
        }
    }

    @Entity
    @Table(name = "TimeEntry")
    @NamedQueries
    ({
        @NamedQuery(name = "TimeEntry.findAll", query = "from TimeEntry t")
    })
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class TimeEntry implements Serializable
    {
        @Id
        @GeneratedValue(strategy=GenerationType.AUTO)
        private Long id;
        private String doneWork;
        private Date beginTime;
        private Date endTime;

        @ManyToOne(targetEntity=Project.class)
        @JoinColumn(name="fk_project") //sets the name of the "FK" column
        private Project project;
       
        @ManyToOne(targetEntity=User.class)
        @JoinColumn(name="fk_user")
        private User user;
    }

    @Entity
    @Table(name = "User")
    @NamedQueries
    ({
        @NamedQuery(name = "User.findAll", query = "from User u")
    })
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User implements Serializable
    {
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
        @Column (unique = true)
        @Basic(optional = false)
        private String username;
        @Basic(optional = false)
        private String password;
       
        @OneToMany(targetEntity = TimeEntry.class,mappedBy="user", cascade = {CascadeType.ALL}, orphanRemoval = true)
        private List<TimeEntry> entries;
       
        public User(String username, String password)
        {
            this.username = username;
            this.password = password;
        }
    }
     
     
  4. Hi musium,

    es ist bei mir schon ne Zeit her dass ich mit Hibernate gearbeitet hab, aber ich würd sagen das sieht ganz gut aus.

    Soweit ich weiß musst du das
    Code (Java):
    @...(targetEntity = TimeEntry.class)
    bei der Annotation nicht angeben, weil die Liste ja vom Typ TimeEntry ist. Das sollte automatisch erkannt werden.

    An dieser Stelle kannst du auch gleich den FetchType mit angeben.
    Z.B.:
    Code (Java):
    @...(fetch=FetchType.EAGER)
    Die Frage nach der Zuordnung der User-Tabelle: Klar, warum nicht? Vom Datenmodel her passt es auf jeden Fall.
    Man könnte sich eventuell noch ein Rollenkonzept überlegen, dann brauchst noch eine Zwischen-Tabelle.
    Aber das soll ja nur exemplarisch sein.

    Die Annotations bei m:n Verknüpfungen sind dann etwas komplizierter, weil man für die Zwischentabelle keine eigene Entity-Klasse braucht.

    Aber wie gesagt, mein Wissen ist nicht 100%ig auf dem neuesten Stand.

    lg
     
  5. Ich seh gerade, dass bei den Attributen die Spalten-Zuweisungen fehlen.

    Code (Java):

    @Column(name="NAME")
    private String name;
     
    Zumindest kenn ich das so :)
     
  6. Hallo,

    Spalten-Zuweisungen sind nur dann notwendig, sofern die Spalten nicht den gleichen Namen erhalten sollen wie die Attribute.
    Bei dieser Thematik wird das Design-Prinzip COC angewandt: Spricht mit Convention over Configuration gearbeitet.
     
  7. [JAVA=11]
    //@ManyToOne(targetEntity = TimeEntry.class) was muss hier hin?
    private List<TimeEntry> entries;
    [/code]
    Das Projekt ist die "Single-valued" Seite der Relation. Deswegen muss da @OneToMany hin! ManyToOne müsste auf die Seite des TimeEntry, wenn es dort ein Feld Projekt gäbe. Nähere Infos gibt's in der Hibernate Doku Chapter*2.*Mapping Entities

    [EDIT]Ahh, ich seh grad, in Deinem zweiten Code-Post stimmt es ja. Bitte diese Antwort ignorieren![/EDIT]
     
    Zuletzt von einem Moderator bearbeitet: 6. Nov. 2012
  8. Code (Java):

    public class TimeEntry implements Serializable
    {
        @Id
        @GeneratedValue(strategy=GenerationType.AUTO)
        private Long id;
        private String doneWork;
        private Date beginTime;
        private Date endTime;
     
        @ManyToOne(targetEntity=Project.class)
        @JoinColumn(name="fk_project") //sets the name of the "FK" column
        private Project project;
       
        @ManyToOne(targetEntity=User.class)
        @JoinColumn(name="fk_user")
        private User user;
    }
    ...
     
    Hier ist ein kleiner Design-Flaw. Weil Du TimeEntry in Project und in User benutzen willst, hast Du hier beide Felder reingebaut. Wenn Du es in Project benutzt, bleibt der User null und umgekehrt. Was, wenn TimeEntry jetzt noch in Event, genutzt werden soll? Kommt das dann auch noch als Feld rein? Du merkst, es ist nicht so ganz gut. Die Lösung ist Generics:
    Code (Java):

    public class TimeEntry<T extends Serializable> {

      private T assignedTo;
    }
     
    In Project verwendest Du dann TimeEntry<Project> und in User TimeEntry<User>. Mit @MappedSuperClass führt das in der DB zur Erstellung mehrerer Tabellen (TimeEntry_User, TimeEntry_Project)
     
  9. Kostenloses Java-Grundlagen Training im Wert von 39 €
    Schau dir jetzt hier das Tutorial an und starte richtig durch!