# Mapping mit Annotations von 2 Tabellen



## cyb0rg (16. Feb 2019)

Hi zusammen,

ich steh auf dem Schlauch, habe folgendes Problem:

Ist Tabellen in der DB:

Table "customer":


```
+----------------+--------------+------+-----+---------+----------------+
| Field          | Type         | Null | Key | Default | Extra          |
+----------------+--------------+------+-----+---------+----------------+
| id             | int(11)      | NO   | PRI | NULL    | auto_increment |
| customernumber | bigint(8)    | NO   | MUL | NULL    |                |
| company        | varchar(250) | YES  |     | NULL    |                |
| salutation     | int(11)      | YES  | MUL | NULL    |                |
| firstname      | varchar(250) | YES  |     | NULL    |                |
| lastname       | varchar(250) | YES  |     | NULL    |                |
| address        | varchar(250) | YES  |     | NULL    |                |
| code           | int(11)      | YES  |     | NULL    |                |
| city           | varchar(250) | YES  |     | NULL    |                |
| country        | varchar(250) | YES  |     | NULL    |                |
| mobile         | varchar(250) | YES  |     | NULL    |                |
| private        | varchar(250) | YES  |     | NULL    |                |
| business       | varchar(250) | YES  |     | NULL    |                |
| email          | varchar(250) | YES  |     | NULL    |                |
| fullname       | varchar(250) | YES  |     | NULL    |                |
| phoneBusiness  | varchar(255) | YES  |     | NULL    |                |
| phonePrivate   | varchar(255) | YES  |     | NULL    |                |
+----------------+--------------+------+-----+---------+----------------+
```

Table "task":


```
+-------------+--------------+------+-----+---------+----------------+
| Field       | Type         | Null | Key | Default | Extra          |
+-------------+--------------+------+-----+---------+----------------+
| id          | int(11)      | NO   | PRI | NULL    | auto_increment |
| tasknr      | bigint(8)    | YES  |     | NULL    |                |
| customer    | int(11)      | YES  | MUL | NULL    |                |
| name        | varchar(250) | YES  |     | NULL    |                |
| description | varchar(250) | YES  |     | NULL    |                |
| categorie   | int(11)      | YES  | MUL | NULL    |                |
| done        | tinyint(1)   | YES  |     | NULL    |                |
| project     | int(11)      | YES  | MUL | NULL    |                |
| bill        | int(11)      | YES  |     | NULL    |                |
| idinvoice   | int(11)      | YES  |     | NULL    |                |
| time        | double       | YES  |     | NULL    |                |
| total       | double       | YES  |     | NULL    |                |
| date        | date         | YES  |     | NULL    |                |
| dateTask    | datetime     | YES  |     | NULL    |                |
| fullName    | varchar(255) | YES  |     | NULL    |                |
+-------------+--------------+------+-----+---------+----------------+
```

Klasse Task.java:


```
@Entity
@Table(name = "task")
public class Task {

    @Id
    @GeneratedValue
    @Column(name = "id")
    private int id;

    private String fullName;

    private long taskNr;

    @Column(name = "name")
    private String name;
    private String description;
    private String categorie;
    private boolean done;
    private boolean bill;
    private double time;
    private double total;
    private Date dateTask;

//    @JoinColumn(name = "id")
//    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
//    private List<Customer> customer;


//    private Customer customer;

    public Task(String fullName, long taskNr, String name, String description, String categorie, Boolean done,
                Boolean bill, double time, double total, Date date) {
        this.fullName = fullName;
        this.description = description;
        this.name = name;
        this.categorie = categorie;
        this.done = done;
        this.taskNr = taskNr;
        this.bill = bill;
        this.time = time;
        this.total = total;
        this.dateTask = date;
//        this.customer = customer;
    }

    public Task() {

    }


//    @OneToOne(cascade = CascadeType.ALL)
//    @JoinTable(
//            name = "customer",
//            joinColumns = @JoinColumn(name="id"),
//            inverseJoinColumns = @JoinColumn(name="customer")
//    )
//
//    @Column
//    @ElementCollection(targetClass = xx.xxx.models.Customer.class)
//    public List<Customer> getCustomer(){
//        return this.customer;
//    }
//
//    public void setCustomer (List<Customer> customer){
//        this.customer = customer;
//    }
```

Die Klasse Customer.java:


```
@Entity
@Table(name="customer")
public class Customer {

    @Id
    @GeneratedValue
    @Column(name="id")
    private int id;

    private long customerNumber;
    private String company;
    private String salutation;
    private String firstName;
    private String lastName;
    private String address;
    private int code;
    private String city;
    private String country;
    private String phonePrivate;
    private String phoneBusiness;
    private String mobile;
    private String email;

    @Column(name="fullname")
    private String fullName;


//    private List<Task> taskList;

    public Customer(){

    }

    public Customer(long customerNumber, String company, String salutation, String firstName, String lastName, String address,
                    int code, String city, String country, String phonePrivate, String phoneBusiness, String mobile,
                    String eMail, String fullName) {
        this.customerNumber = customerNumber;
        this.company = company;
        this.salutation = salutation;
        this.firstName = firstName;
        this.lastName = lastName;
        this.address = address;
        this.code = code;
        this.city = city;
        this.country = country;
        this.phonePrivate = phonePrivate;
        this.phoneBusiness = phoneBusiness;
        this.mobile = mobile;
        this.email = eMail;
        this.fullName = fullName;
    }

//    public void setTaskList(List<Task> taskList){
//        this.taskList = taskList;
//    }

//    @ManyToMany(cascade = CascadeType.ALL)
//    @JoinTable(name = "task")
//    public List<Task> getTaskList(){
//        return this.taskList;
//    }
```
Zum Verständnis:

So wie es jetzt gepostet ist, werden beiden Klassen geladen und die GUI Befüllt wie erwartet.

Ihr seht da Kommentierte Join statements... ich versuche entsprechend die Richtigen informationen zusammenzustellen, habe einiges an Literatur gelesen doch leider noch keine für mich funktionierende Lösung...

Wenn ich versuche die Tabellen zusammen zu führen habe ich folgende Error Meldung in der Console:


```
org.hibernate.AnnotationException: @OneToOne or @ManyToOne on xx.xxx.models.Task.customer references an unknown entity: java.util.List
```

Der funktionierende SQL Query String ist:


```
String query = "select task.id, task.tasknr, customer.fullname as fullname, task.name, task.description, " +
        "task.done, task.project, categorie.name as categorie\n, task.bill, task.time, task.total, task.date " +
        "from task\n" +
        "left join categorie on task.categorie = categorie.id " +
        "left join customer on task.customer = customer.id";
```

Wobei ich die categorie noch auslasse, muss es erst mit dem Task und Customer zum laufen kriegen.

habt ihr eine idee?


----------



## mihe7 (17. Feb 2019)

Du hast eine 1:n-Beziehung zwischen Customer und Task. Dem entsprechend gehört zu einem Task nur ein Customer-Objekt und keine Liste von Customer-Objekten. 

Task:

```
@ManyToOne
    private Customer customer;
```

Customer:

```
@OneToMany(mappedBy="customer")
    private List<Task> tasks;
```


----------



## cyb0rg (17. Feb 2019)

vielen dank mihe7!

jedoch erscheint mir bei der abfrage noch keine zusammenführung stattgefunden zu haben?


```
tableColumnTaskDate.setCellValueFactory(new PropertyValueFactory<Task, Date>("dateTask"));
tableColumnCustomer.setCellValueFactory(new PropertyValueFactory<Customer, String>("fullName"));
tableColumn01.setCellValueFactory(new PropertyValueFactory<Task, String>("name"));
tableColumn02.setCellValueFactory(new PropertyValueFactory<Task, String>("description"));
tableColumn03.setCellValueFactory(new PropertyValueFactory<Task, String>("categorie"));
tableColumn04.setCellValueFactory(new PropertyValueFactory<Task, Boolean>("done"));

tableViewMain.setItems(getTasks());
```

die getTasks Funktion:


```
private ObservableList<Task> getTasks() throws SQLException {
        ObservableList<Task> tasksList = FXCollections.observableArrayList();

        Configuration cfg = new Configuration().configure("/configs/hibernate.cfg.xml");
        SessionFactory sessionFactory = cfg.buildSessionFactory();


        Session session = sessionFactory.openSession();
        Transaction tx = null;

        try {
            tx = session.beginTransaction();
            List tasks = session.createQuery("FROM Task").list();
            for (Iterator iterator = tasks.iterator(); iterator.hasNext();){
                Task task = (Task) iterator.next();
                System.out.println("Task Nr: " + task.getTaskNr());
            }
            tasksList = FXCollections.observableArrayList(session.createQuery("FROM Task").list());
            tx.commit();
        } catch (HibernateException e) {
            if (tx!=null) tx.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }

//        SqlHelperTasks SqlHelper = new SqlHelperTasks();

//        tasks = SqlHelper.getTasks();
        return tasksList;
    }
```


----------



## mihe7 (17. Feb 2019)

Das ist seltsam, denn standardmäßig wird eine ManyToOne sofort geladen (fetch=FetchType.EAGER). Probier mal folgende Abfrage: "SELECT t FROM Task t LEFT JOIN FETCH t.customer c".

Übrigens: Du führst die Abfrage aktuell doppelt aus. Das muss nicht sein. Eine ObservableList ist auch nur eine List.

EDIT: LEFT JOIN verwendet.


----------



## cyb0rg (17. Feb 2019)

nach wie vor wird Customer nicht geladen.

ja ich weiss 
die zweite abfrage ist lediglich für einen sysoutput 

output von console:

```
Hibernate: 
    select
        task0_.id as id0_0_,
        customer1_.id as id1_1_,
        task0_.bill as bill0_0_,
        task0_.categorie as categorie0_0_,
        task0_.customer_id as customer11_0_0_,
        task0_.dateTask as dateTask0_0_,
        task0_.description as descript5_0_0_,
        task0_.done as done0_0_,
        task0_.name as name0_0_,
        task0_.taskNr as taskNr0_0_,
        task0_.time as time0_0_,
        task0_.total as total0_0_,
        customer1_.address as address1_1_,
        customer1_.city as city1_1_,
        customer1_.code as code1_1_,
        customer1_.company as company1_1_,
        customer1_.country as country1_1_,
        customer1_.customerNumber as customer7_1_1_,
        customer1_.email as email1_1_,
        customer1_.firstName as firstName1_1_,
        customer1_.fullname as fullname1_1_,
        customer1_.lastName as lastName1_1_,
        customer1_.mobile as mobile1_1_,
        customer1_.phoneBusiness as phoneBu13_1_1_,
        customer1_.phonePrivate as phonePr14_1_1_,
        customer1_.salutation as salutation1_1_ 
    from
        task task0_ 
    left outer join
        customer customer1_ 
            on task0_.customer_id=customer1_.id
```


----------



## mihe7 (17. Feb 2019)

cyb0rg hat gesagt.:


> nach wie vor wird Customer nicht geladen.


Steht denn in der DB-Tabelle für die Tasks überhaupt ein Customer drin?


----------



## cyb0rg (17. Feb 2019)

ja  es gibt kein task ohne customer


----------



## mihe7 (17. Feb 2019)

Das Problem muss an anderer Stelle sein. Um ganz sicher zu gehen, kannst Du ja spaßeshalber mal unmittelbar vor dem `return taskList;` noch einfügen:

```
for (Task t : taskList) {
    System.out.println(t.getId() + ": " + (t.getCustomer() == null ? "-----" : t.getCustomer().getId()));
}
```


----------



## cyb0rg (17. Feb 2019)

ja das denke ich auch aber wo? 


```
1: -----
2: -----
3: -----
4: -----
5: -----
6: -----
7: -----
8: -----
9: -----
10: -----
11: -----
12: -----
13: -----
14: -----
15: -----
16: -----
```

was mir noch nich klar ist, wie weiss aufgrund der annotations hibernate, dass es Customer joinen muss?


----------



## mihe7 (17. Feb 2019)

cyb0rg hat gesagt.:


> was mir noch nich klar ist, wie weiss aufgrund der annotations hibernate, dass es Customer joinen muss?


S. Kommentar #2: `@ManyToOne Customer customer` ist doch ziemlich eindeutig 

S. Kommentar #4: Task LEFT JOIN FETCH Customer


----------



## mihe7 (17. Feb 2019)

Ich bau mal schnell was zusammen.


----------



## cyb0rg (17. Feb 2019)

big thx man!


----------



## mrBrown (17. Feb 2019)

Passen die Fremdschlüssel?

Wenn ich das grad richtig sehe, heißt der in der Task-Tabelle customer, in den späteren Statements steht aber customer_id (kann aber gut sein, das ich grad völlig falsch gelesen habe und denke...)


----------



## cyb0rg (17. Feb 2019)

also der key in der Task Tabelle heisst customer richtig.

dieser referenziert die Spalte Id von der Tabelle Customer.

ich bin der meinung dass es stimmt, ansosten würde mein SQL Statement nicht funktionieren.


----------



## mihe7 (17. Feb 2019)

S. Anhang. Funktioniert einwandfrei.


----------



## cyb0rg (17. Feb 2019)

leider...
java -jar hbtest-src.jar
no main manifest attribute, in hbtest-src.jar

wenndu mir aber die source gibst, dann kann ich es mir anschauen


----------



## mihe7 (17. Feb 2019)

Das ist der Source  Nachtrag: ein jar ist einfach ein zip. Kannst es einfach umbenennen.


----------



## cyb0rg (17. Feb 2019)

hab ich grad realisiert  bin grad dabei es mir anzuschauen thx!


----------



## mrBrown (17. Feb 2019)

cyb0rg hat gesagt.:


> ich bin der meinung dass es stimmt, ansosten würde mein SQL Statement nicht funktionieren.


Weiß Hibernate auch, dass die Spalte customer und nicht customer_id heißt?

In der von dir gezeigten Konsolenausgabe steht `task0_.customer_id` und eben nicht nur `task0_.customer` (wie es auch in deinem eigenen SQL-Statement steht)


----------



## cyb0rg (17. Feb 2019)

zwischen demo code von mihe7 und dein input mrBrown.. hab ich das nun auch "realisiert".

ich hab in der DB nun zwecks test die Spalte angepasst und dessen name von customer zu customer_id umgestellt:

siehe da, ein schritt weiter!


```
1: 26
2: 27
3: 26
4: 29
5: 27
6: 29
7: 29
8: 29
9: 27
10: 27
11: 27
12: 29
13: 27
14: 27
15: 26
16: 27
17: 26
18: 26
19: 31
20: 31
```

also es wird nun tatsächlich eine id ausgelesen.

Im Debug modus habei ch auch die objekte anschauen können es sind tatsächlcih die entsprechende einträge drinn.

das nächste ist zu wissen wieso es nicht in der tableview angezeigt wird?


----------



## mihe7 (17. Feb 2019)

Was mich viel mehr interessieren würde: wieso führt Deine DB klaglos:

```
from
        task task0_ 
    left outer join
        customer customer1_ 
            on task0_.customer_id=customer1_.id
```
aus, wenn task.customer_id nicht existiert?


----------



## cyb0rg (17. Feb 2019)

ich habe diesbezüglich inder DB gesehen, dass die spalten generiert wurden, hat mich etwas überrascht aber bin eben noch neu in jpa welt


----------



## cyb0rg (19. Feb 2019)

Nachtrag:

die Spalte wird nun auch ausgefüllt!


```
tableColumnCustomer.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getCustomer().getFullName()));
```

zwar meiner Meinung nach keine elegante Lösung, aber es funktioniert.


----------

