# Join Abfrage



## Generic1 (30. Okt 2010)

Hallo,

ich steh gerade auf der Leitung was eine SQL- Abfrage über 2 Tabellen betriffe:
Meine 2 Tabellen schauen so aus: 


```
TParticipant
-------------
firstname
surname
fk_address


TAddress
-----------
pk_address
zipcode
city
```

Ich möchte nun eine Abfrage machen, mit der ich alle Participants bekomme, die einen bestimmten Vor- oder Nachnamen haben oder in einer bestimmten Stadt wohnen.
Folgende Abfrage hab ich bis jetzt:


```
SELECT * FROM  TParticipant WHERE TParticipant.firstname LIKE '%Hans%' OR TParticipant.surname LIKE '%Weizer%';
```

Mit der Abfrage bekomme ich aml alle Teilnehmer, die Hans oder Weizer im Namen haben, ich möchte aber jetzt auch noch die Teilnehmer bekommen, die  an einem bestimmten Ort (TAddress.city) wohnen.
Wäre dankbar, wenn mir da jemand helfen könnte.
lg


----------



## Marcinek (30. Okt 2010)

```
SELECT * FROM  TParticipant, TAddress
 WHERE TAddress
.pk_adress =TParticipant.fk_adress and (TParticipant.firstname LIKE '%Hans%' OR TParticipant.surname LIKE '%Weizer%' or TAdress.city like '%bar%');
```


----------



## Generic1 (30. Okt 2010)

Besten Dank, das funktioniert, wenn ich dieses SQL in der DB absetzt,

Was ich jetzt noch nicht versteh ist, wenn ich das so machen:


```
final String searchQuery = " from " + PARTICIPANT + " as p, " + ADDRESS + " as a where a.pk_address = p.fk_address AND (p.firstname LIKE '%" + name + "%' OR p.surname LIKE '%" + name + "%' OR a.city LIKE '%" + name + "%')";
```

dann bekomme ich folgende Exception: 

hibernate3.HibernateQueryException: could not resolve property: fk_address of: at.eventtiming.participant.domain.Participant 

Weiß jemand was ich da falschmache? 
Vielen Dank, 
lg


----------



## Gelöschtes Mitglied 5909 (30. Okt 2010)

In deinem Entity Participant gibt es keine property fk_address

Wenn du dich an die Conventions hälst, wird sie warscheinlich fkAdress heißen


----------



## Generic1 (30. Okt 2010)

Naja, ganz versteh ichs nicht, die Klasse Participant schaut bei mir so aus:


```
@SuppressWarnings("serial")
@Table(name="TParticipant")
public class Participant implements Serializable {

  private Integer pk_part;
  private String firstname;
  private String surname;
  private String chipnumber;
  private Contact contact;
  private int fk_paid;
  private Paid paid;
  private int fk_result;
  private Result result;
  private int fk_club;
  private Club club;
  private int fk_gender;
  private Gender gender;
  private int fk_address;
  private Address address;
  private int fk_born;
  private Born born;
  private Collection<Event> events;
  
  public Participant() {
    events = new ArrayList<Event>();
    }

  @Id
  @GeneratedValue(generator="foreign")
  @GenericGenerator(name="foreign", strategy = "foreign", parameters={
        @Parameter(name="property", value="contact")
        })
  public Integer getPk_part() {
        return pk_part;
        }

  public void setPk_part(final Integer pk_part) {
        this.pk_part = pk_part;
        }

  /* Contact 1:1 */
  @OneToOne(optional=true)
  @PrimaryKeyJoinColumn
  public Contact getContact() {
        return contact;
        }

  public void setContact(final Contact contact) {
        this.contact = contact;
        }

  /* Primarykey Generator is only possible once, therefore a separate colomn: 1:1 relation */
  @OneToOne(cascade = CascadeType.ALL)
  @JoinColumn(name="fk_paid")
  public Paid getPaid() {
        return paid;
        }

  public void setPaid(Paid paid) {
        this.paid = paid;
        }

  /* 1:1 relation  */
  @OneToOne(cascade = CascadeType.ALL, fetch=FetchType.EAGER)
  @JoinColumn(name="fk_result")
  public Result getResult() {
        return result;
        }

  public void setResult(final Result result) {
        this.result = result;
        }

  /* 1:n relation */
  @ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)  // CascadeType.ALL muss hier so angegeben werden da ansonsten zuerst der Club gespeichert werden muss um diesen dann zum Participant hinzufügen zu können
  @JoinColumn(name="fk_club")
  public Club getClub() {
        return club;
        }

  public void setClub(final Club club) {
        this.club = club;
        }

  /* 1:n relation */
  @ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)  // CascadeType.ALL muss hier so angegeben werden da ansonsten zuerst der Club gespeichert werden muss um diesen dann zum Participant hinzufügen zu können
  @JoinColumn(name="fk_born")
  public Born getBorn() {
        return born;
        }

  public void setBorn(final Born born) {
        this.born = born;
        }

  @ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
  @JoinColumn(name="fk_gender")
  public Gender getGender() {
        return gender;
        }

  public void setGender(Gender gender) {
        this.gender = gender;
        }

  @ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
  @JoinColumn(name="fk_address")
  public Address getAddress() {
        return address;
        }

  public void setAddress(Address address) {
        this.address = address;
        }
```


----------



## Gast2 (30. Okt 2010)

Nebenbei bemerkt:


```
LIKE '%Hans%'
```

Ist immer eine ganz schlechte Idee. Wenn du das Pattern mit einem Wildcard anfängst kann die Datenbank keine Indexstrukturen nutzen und macht einen Fulltablescan - sprich die Performance geht in den Keller.


----------



## Generic1 (30. Okt 2010)

OK, besten Dank, aber momentan interessiert mich mehr, warum meine Abfrage nicht funktioniert.
Gibts da einen Vorschlag wie ich das lösen kann?


----------



## Gast2 (30. Okt 2010)

Lass dir mal den String 

```
final String searchQuery = " from " + PARTICIPANT + " as p, " + ADDRESS + " as a where a.pk_address = p.fk_address AND (p.firstname LIKE '%" + name + "%' OR p.surname LIKE '%" + name + "%' OR a.city LIKE '%" + name + "%')"
```

in ein Log schreiben. Wie sieht der Query aus wenn alles eingesetzt ist? Funktioniert er dann auch direkt über den SQL Navigator o.Ä.?

Dieses Query zusammenkonkatenieren ist immer höchst unleserlich und meist fehlerträchtig 

Evtl passen die Konstanten Namen nicht, Hochkommas in [c]name[/c] - oder sowas ähnliches...


----------



## Generic1 (31. Okt 2010)

Hallo,

die Fehlermeldung schaut dann so aus:


```
could not resolve property:
```

vielleicht hab ich was übersehen aber schaut eigentlich ganz gut aus, oder sieht jemand einen Fehler?
Vielen Dank,
lg


----------



## mvitz (31. Okt 2010)

Hast du die Klasse oben selber geschrieben?

Er kann auch die Properties nicht finden!!! Du hast die Getter/Setter Annotiert, damit kann man nur noch Properties über Getter/Setter ansprechen und die hast du werder für a.pk_address noch für p.fk_address.

Diese hasst du übrigens auch nicht für Firstname und Surname (zumindest nicht, wenn das Listing Vollständig ist)


----------



## Generic1 (31. Okt 2010)

Die Klassen oben sind von mir, ich weiß aber jetzt nciht, was ich in diese Klassen dazumachen muss.
Hier die 2 kompletten Klassen:


```
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;

@Entity
@SuppressWarnings("serial")
@Table(name="TParticipant")
public class Participant implements Serializable {

  private Integer pk_part;
  private String firstname;
  private String surname;
  private String chipnumber;
  private Contact contact;
  private int fk_paid;
  private Paid paid;
  private int fk_result;
  private Result result;
  private int fk_club;
  private Club club;
  private int fk_gender;
  private Gender gender;
  private int fk_address;
  private Address address;
  private int fk_born;
  private Born born;
  private Collection<Event> events;
  
  public Participant() {
    events = new ArrayList<Event>();
    }

  @Id
  @GeneratedValue(generator="foreign")
  @GenericGenerator(name="foreign", strategy = "foreign", parameters={
        @Parameter(name="property", value="contact")
        })
  public Integer getPk_part() {
        return pk_part;
        }

  public void setPk_part(final Integer pk_part) {
        this.pk_part = pk_part;
        }

  /* Contact 1:1 */
  @OneToOne(optional=true)
  @PrimaryKeyJoinColumn
  public Contact getContact() {
        return contact;
        }

  public void setContact(final Contact contact) {
        this.contact = contact;
        }

  /* Primarykey Generator is only possible once, therefore a separate colomn: 1:1 relation */
  @OneToOne(cascade = CascadeType.ALL)
  @JoinColumn(name="fk_paid")
  public Paid getPaid() {
        return paid;
        }

  public void setPaid(Paid paid) {
        this.paid = paid;
        }

  /* 1:1 relation  */
  @OneToOne(cascade = CascadeType.ALL, fetch=FetchType.EAGER)
  @JoinColumn(name="fk_result")
  public Result getResult() {
        return result;
        }

  public void setResult(final Result result) {
        this.result = result;
        }

  /* 1:n relation */
  @ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)  // CascadeType.ALL muss hier so angegeben werden da ansonsten zuerst der Club gespeichert werden muss um diesen dann zum Participant hinzufügen zu können
  @JoinColumn(name="fk_club")
  public Club getClub() {
        return club;
        }

  public void setClub(final Club club) {
        this.club = club;
        }

  /* 1:n relation */
  @ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)  // CascadeType.ALL muss hier so angegeben werden da ansonsten zuerst der Club gespeichert werden muss um diesen dann zum Participant hinzufügen zu können
  @JoinColumn(name="fk_born")
  public Born getBorn() {
        return born;
        }

  public void setBorn(final Born born) {
        this.born = born;
        }

  @ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
  @JoinColumn(name="fk_gender")
  public Gender getGender() {
        return gender;
        }

  public void setGender(Gender gender) {
        this.gender = gender;
        }

  @ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
  @JoinColumn(name="fk_address")
  public Address getAddress() {
        return address;
        }

  public void setAddress(Address address) {
        this.address = address;
        }

  @ManyToMany(
        fetch=FetchType.EAGER,       /* load all objects immediately, standard is lazy */
        targetEntity=at.eventtiming.participant.domain.Event.class,
        cascade=CascadeType.ALL)
  @JoinTable(
        name="TEvent_TParticipant",
        joinColumns=@JoinColumn(name="id_part"),
        inverseJoinColumns=@JoinColumn(name="id_event")
        )
  public Collection<Event> getEvents() {
        return events;
        }

  public void setEvents(final Collection<Event> events) {
        this.events = events;
        }

  public String getFirstname() {
        return firstname;
        }

  public void setFirstname(final String firstname) {
        this.firstname = firstname;
        }

  public String getSurname() {
        return surname;
        }

  public void setSurname(final String surname) {
        this.surname = surname;
        }

  public String getChipnumber() {
        return chipnumber;
        }

  public void setChipnumber(final String chipnumber) {
        this.chipnumber = chipnumber;
        }
  
  @Override
  public boolean equals(final Object o) {
        if (o instanceof Participant) {
            final Participant rant = (Participant) o;
            return rant.pk_part.equals(this.pk_part);
            }
        else
            return false;
        }
  
  @Override
  public int hashCode() {
        return super.hashCode();
        }

  @Override
  public String toString() {
        return "[" + pk_part + ", " + firstname +  ", " + surname + ", " + chipnumber + ", Contact: " + contact +
                ", Paid: " + paid + ", Club: " + club + ", Gender " + gender + ", Address: " + address +
                ", Event: " + events + ", Result: " + result + "]";
        }
}
```


```
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="TAddress")
public class Address implements Serializable {

    private Integer pk_address;
    private String street;
    private Integer zipcode;
    private String city;
    private String nationality;
    private String country;

    public Address() {}

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    public Integer getPk_address() {
        return pk_address;
        }

    public void setPk_address(Integer pk_address) {
        this.pk_address = pk_address;
        }

    public String getStreet() {
        return street;
        }

    public void setStreet(String street) {
        this.street = street;
        }

    public Integer getZipcode() {
        return zipcode;
        }

    public void setZipcode(Integer zipcode) {
        this.zipcode = zipcode;
        }

    public String getCity() {
        return city;
        }

    public void setCity(String city) {
        this.city = city;
        }

    public String getNationality() {
        return nationality;
        }

    public void setNationality(String nationality) {
        this.nationality = nationality;
        }

    public String getCountry() {
        return country;
        }

    public void setCountry(String country) {
        this.country = country;
        }

    @Override
    public boolean equals(final Object obj) {
        if(obj == null)
            return false;
        else if(obj instanceof Address) {
            final Address that = (Address)obj;
            if(this.street.trim().equals(that.street.trim()) &&
               this.city.trim().equals(that.city.trim()) &&
               this.nationality.trim().equals(that.nationality.trim()) &&
               this.zipcode.intValue() == that.zipcode.intValue()) {
                return true;
                }
            }
        return false;
        }

    @Override
    public int hashCode() {
        int hash = 3;
        hash = 17 * hash + (this.street != null ? this.street.hashCode() : 0);
        hash = 17 * hash + (this.zipcode != null ? this.zipcode.hashCode() : 0);
        hash = 17 * hash + (this.city != null ? this.city.hashCode() : 0);
        hash = 17 * hash + (this.nationality != null ? this.nationality.hashCode() : 0);
        return hash;
    }

    @Override
    public String toString() {
        return "[" + pk_address + ", " + street + ", " + zipcode + ", " + city + ", " + nationality + ", " + country + "]";
        }
}
```


----------



## mvitz (31. Okt 2010)

Ist das Datenbankschema so vorgegeben oder hast du da freie Wahl?

Ansonsten versuche mal:


```
" from " + PARTICIPANT + " as p where p.firstname LIKE '%" + name + "%' OR p.surname LIKE '%" + name + "%' OR p.address.city LIKE '%" + name + "%')"
```


----------



## mvitz (31. Okt 2010)

Also folgendes Minimalbeispiel funktioniert bei mir:


```
package de.mvitz.examples.eclipselink;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
@SuppressWarnings("serial")
public class Address implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String city;

    public Integer getId() {
        return id;
    }

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

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

}
```


```
package de.mvitz.examples.eclipselink;

import java.io.Serializable;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

@Entity
@SuppressWarnings("serial")
public class Participant implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String firstname;
    private String surname;
    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private Address address;

    public Integer getId() {
        return id;
    }

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

    public String getFirstname() {
        return firstname;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

}
```


```
package de.mvitz.examples.eclipselink;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Persistence;
import javax.persistence.TypedQuery;

public class Test {

    public static void main(String[] args) {
        Address a1 = new Address();
        a1.setCity("Test");

        Address a2 = new Address();
        a2.setCity("Test2");

        Participant p1 = new Participant();
        p1.setFirstname("F1");
        p1.setSurname("S1");
        p1.setAddress(a1);

        Participant p2 = new Participant();
        p2.setFirstname("P2");
        p2.setSurname("S2");
        p2.setAddress(a2);

        EntityManager em = Persistence.createEntityManagerFactory("de.mvitz.examples.eclipselink")
                .createEntityManager();
        em.getTransaction().begin();
        em.persist(p1);
        em.persist(p2);
        em.getTransaction().commit();

        String name = "es";

        TypedQuery<Participant> query = em.createQuery(
                "SELECT p FROM Participant p WHERE p.firstname LIKE '%" + name
                        + "%' OR p.surname LIKE '%" + name + "%' OR p.address.city LIKE '%" + name
                        + "%'", Participant.class);
        List<Participant> ps = query.getResultList();
        System.out.println(ps);
    }

}
```


----------

