1:n Beziehung ralisieren

Diskutiere 1:n Beziehung ralisieren im Application Tier Forum; Ich hätte gerne dass die User Entities in meiner Applikation Rezepte anlegen können. Es handelt sich also um eine 1:n-Beziehung. Dazu habe ich...

  1. markai
    markai Neues Mitglied
    Ich hätte gerne dass die User Entities in meiner Applikation Rezepte anlegen können. Es handelt sich also um eine 1:n-Beziehung. Dazu habe ich folgendes gemacht:

    Code (Java):

    @Entity @Table(name="Users")
    public class User implements Serializable {
       
        private static final long serialVersionUID = 1L;
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
        private String firstname;
        @Column(nullable=false) @NotBlank @Pattern(regexp="\\D+", message="no numbers allowed")
        private String lastname;
     
        private List<Recipe> recipes = new ArrayList<>();
        @Column(nullable=false) @NotBlank
     
    Code (Java):

    @Entity
    public class Recipe implements Serializable, Comparable<Recipe> {
        private static final long serialVersionUID = 1L;
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
        @Column(nullable=false) @NotBlank
        private String name;
        @Column(nullable=false) @NotBlank
        @Lob
        private String description;
        @ManyToMany(fetch= FetchType.EAGER) @Valid
        private List<Ingredients> ingredients = new ArrayList<>();
        @ElementCollection @Valid
        private List<Comment> comments = new ArrayList<>();
     
    Ich hab jetzt zwar einen RecipeController und einen UserController mit dem ich User und auch Recipes anlegen kann, aber wie funktioniert die Zuordnung? Ich hätte gerne
    Code (Text):
    recipes.add(new Recipe)
    in meinem UserController gemacht, aber das funktioniert ja nicht.
    Ich verwende die derby db und jsf.
     
  2. Vielleicht hilft dir dieser Kurs hier weiter --> (hier klicken)
  3. diel2001
    diel2001 Neues Mitglied
    Vielleicht so ?
    Code (Java):

    @ManyToOne
    private List<Recipe> recipes = new ArrayList<>();
     
     
  4. markai
    markai Neues Mitglied
    Sry hab versehentlich die Annotation beim kopieren rausgelöscht. Hatte

    Code (Java):

        @OneToMany
        private List<Recipe> recipes = new ArrayList<>();
     
    (Ein User soll ja mehrere Rezepte anlegen können.) Hab dann zwar eine Zwischentabelle "USER_RECIPE" mit den Attributen "USER_ID" und "RECIPE_ID" aber keinen Plan wie ich die Zuordnen soll. Gibt doch sicher eine Möglichkeit dass das JPA das für mich macht?
     
  5. cljk
    cljk Guest
    Du hast eine 1:n und keine n:n Zuordnung. Daher ist eine Zwischentabelle nicht notwendig.

    Du wirst User haben (1), die jew. mehrere Rezepte zugeordnet bekommen (n).

    Erweitere deine Recipe-Klasse um das Feld User z.B.
    Code (Java):

    @ManyToOne
    @JoinColumn(name="CREATED_BY_USER")
    User createdByUser;
     
    und in deiner User-Klasse beziehst du dich in umgek. Notation auf die Receipe-Klasse
    Code (Java):

    @OneToMandy(mappedBy="createdByUser")
    List<Receipe> receipesOfUser;
     
    Eine Initialisierung mit = new ArrayList... solltest du ggf. sein lassen, außer du brauchst das. Beim Laden aus der DB bekommst du eh nur Objekte mit initialisierten (ggf. leeren) Listen zurück.


    Gruß

    Marcel
     
  6. markai
    markai Neues Mitglied
    Ok die Zwischentabelle ist wohl von einem früheren Versuch übrig geblieben. Danke für den Tipp! Zuordnung funktioniert bestens :toll:

    Jetzt hätte ich noch gerne dass auf meiner "home" Seite ALLE Rezepte angezeigt werden.
    Code (Java):

    @ManagedBean(name = "recipeController")
    @SessionScoped
    public class RecipeController implements Serializable {
        ...
        public List<Recipe> getAllRecipes() {
            List result = getFacade().getEntityManager().createQuery("select r from Recipe r").getResultList();
            return result;
     
    ... was bestens funktioniert. Auf dem jeweiligen Benutzerprofil sollen aber nur eigene Rezepte angezeigt werden:

    Code (Java):

    ...
    SessionBean sessionBean = (SessionBean) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("sessionBean");

        public List<Recipe> getMyRecipes() {
            List result = getFacade().getEntityManager().createQuery("select r from Recipe r where USER_ID = "+sessionBean.getCurrentUser().getId()).getResultList();
            return result;
     
    was folgende Exception wirft:

    Code (Java):

    javax.el.ELException: /pages/myProfile.xhtml @34,49 value="#{recipeController.myRecipes}": java.lang.IllegalArgumentException: An exception occurred while creating a query in EntityManager:
    Exception Description: Error compiling the query [select r from Recipe r where USER_ID = 1], line 1, column 29: unknown identification variable [user_id]. The FROM clause of the query does not declare an identification variable [user_id].
        at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:114)
        at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:194)
        at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:182)
        at javax.faces.component.UIData.getValue(UIData.java:731)
        at org.primefaces.component.datatable.DataTable.getValue(DataTable.java:773)
        at javax.faces.component.UIData.getDataModel(UIData.java:1798)
        at javax.faces.component.UIData.getRowCount(UIData.java:356)
        at org.primefaces.component.api.UIData.calculatePage(UIData.java:127)
     
    (In der sessionBean wird der aktuelle User gespeichert.) Was mache ich falsch?
     
  7. cljk
    cljk Neues Mitglied
    Also das einfachste(!) da du die Relation definiert hast ist ja, den User zu laden und über das User-Objekt mit getReceipes() (oder wie es heisst) auf die Rezepte zuzugreifen.
    Code (Java):

    sessionBean.getCurrentUser().getReceipes()
     
    Die Lösung die du da nutzt, geht auch... du solltest aber daran denken, dass du JPA nutzt und nicht SQL. JPA kennt die Column-Names etc nicht. Ich mag grad nicht nachschlagen - aber du schreibst etwas in der Art wie

    Code (Java):

    Query q = getFacade().getEntityManager().createQuery("select r from Recipe r where r.createdByUser = :user");
    q.setParameter("user", sessionBean.getCurrentUser());
    return q.getResultList();
     

    Im übrigen ist auch obiges relativ gesehen Mist. Queries gehören in Transaktionen und damit nicht in die Managementbean sondern in die SessionBean. Der EJB-Container bastelt dann automatisch eine Transaktion drum.

    Und noch eine Anmerkung.
    Code (Java):

    SessionBean sessionBean = (SessionBean) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("sessionBean");
     
    kannste dir vermutlich sparen. Ist das eine RequestScope- ManagementBean?
    Dann kannste auch einfach schreiben.

    Code (Java):

    @ManagedProperty(value="#{sessionBean}")
    SessionBean sessionBean
     
    Die sollte dann automatisch injiziert werden - vorausgesetzt der Name stimmt.
     
  8. markai
    markai Neues Mitglied
    Ist ja direkt peinlich dass ich nicht selbst dran gedacht hab... Jedenfalls funktioniert es so.

    Die sessionBean verwende ich um mein User-Objekt zu speichern wenn dieser sich anmeldet.
    Code (Java):

    @SessionScoped
    @ManagedBean(name="sessionBean")
    public class SessionBean implements Serializable {
       
        private User currentUser;

    // getter u setter
        }
     
    Ist zwar vermutlich nicht schön, aber es war die einzige Lösung die mir eingefallen ist... Du meinst also dass Tranksaktionen auch in meine sessionBean rein gehören? Wäre für Verbesserungsvorschläge dankbar.
     
  9. cljk
    cljk Neues Mitglied
    Nene... jetzt hauen wir gerade zwei Sachen durcheinander (JSF-SessionBean und Stateless Session Bean).

    Ich bin davon ausgegangen, dass "getFacade()" dir einen StatelessSessionBean (EJB) zurück gibt. Ist das so?
    Wenn ja - gehört die JPA-Anfrage als Methode definitiv da rein und von "getEntityManager" hast du dann auf JSF-Seite die Finger zu lassen. Der EntityManager wäre dann nur gültig für den Kontext der EJB und soll nicht weitergegeben werden - auch wenn es aktuell funktioniert.
    Wenn du allerdings alles irgendwie in JSF Request- und SessionBeans abwickelst, ist das zwar definitiv nicht schön - kann dann bei dem einfachen Projekt so bleiben.
     
  10. markai
    markai Neues Mitglied
    Das ist meine Facade.
    Code (Java):

    @Stateless
    public class RecipeFacade extends AbstractFacade<Recipe> {
        @PersistenceContext(unitName = "cookItLikeABoss_PU")
        private EntityManager em;

        @Override
        public EntityManager getEntityManager() {
            return em;
        }

        public RecipeFacade() {
            super(Recipe.class);
        }
    }
     
    Verstehe ich das richtig? Ich soll meine queries da reinschreiben und diese dann vom RecipeController aus aufrufen?
     
  11. cljk
    cljk Neues Mitglied
    Absolut - Queries gehören in einem JavaEE-Projekt immer in EJBs.

    Der Sinn von StatelessSessionBeans (inbes. bei sog. Fassaden) ist u.a. die Behandlung der Datenspeicherung. Alles andere geht - wie du siehst - auch - ist aber ganz böser Stil.


    Ich weiss nicht wo du die Oberklasse AbstractFacade her hast - aber da würde ich getEntityManager auf "protected" statt "public" setzen. Dann siehst du recht schnell, was geändert werden muss - weils nämlich nicht mehr läuft *g. Ich vermute mal einfach, dass AbstractFacade manche Basis-Methoden für den Datenzugriff definieren wie z.B. "findByPrimaryKey" o.ä. und "getEntityManager" benötigt, um den EntityManager der Subklassen zu beziehen. Das ist aber nicht für die JSF-Klassen gedacht.

    Also "getAllRecipes()" gehört *definitiv* in die EJB - wenn du getMyReceipes jetzt nur über den Objektzugriff regelst, kannst das in der ManagedBean lassen - mit der Querie-Variante muss das sonst aber def. auch dahin.
    Den Benutzer wirst du ja vermutlich auch über eine Fassade (und damit einer EJB) suchen.

    Auf JSF-Seite rufst die Methoden passend auf und leitest das Ergebnis weiter. Ist 3 Zeilen Mehrarbeit - lohnt sich aber - und schöner strukturiert ist es allemale.


    So, ich geh jetzt in die Sonne - schönen Sonntag noch.
     
Die Seite wird geladen...

1:n Beziehung ralisieren - Ähnliche Themen

Beziehung Interface - (abstrakte) Klasse -Unterklasse
Beziehung Interface - (abstrakte) Klasse -Unterklasse im Forum Java Basics - Anfänger-Themen
JSTree in Web-App: Datenbank-Beziehungen verschwinden nach unbestimmter Zeit
JSTree in Web-App: Datenbank-Beziehungen verschwinden nach unbestimmter Zeit im Forum Allgemeines EE
DBS Relationenmodell zwingende Beziehung
DBS Relationenmodell zwingende Beziehung im Forum Hausaufgaben
Datenbanken RM Modell IST-Beziehung auflösen
Datenbanken RM Modell IST-Beziehung auflösen im Forum Hausaufgaben
JPA Entities und deren Beziehungen modellieren
JPA Entities und deren Beziehungen modellieren im Forum Application Tier
Thema: 1:n Beziehung ralisieren