# JPA: Nach String statt Primärschlüssel suchen



## Tabkas (16. Okt 2019)

Abend,

also bei JPA. Mit:

em.find(Tabelle.class, query) 

kann man ja suchen, aber eben nur nach Primärschlüsselwerten.

Was, wenn ich nun zB einfach nach einem Wert suchen will? Also eine SELECT WHERE LIKE Abfrage senden will, aber eben mit JPA?

Google gab mir sowas wie: 

@Query("SELECT u.username FROM User u WHERE u.username LIKE CONCAT('%',:username,'%')")
    List<User> findByUserLike(String user);

Ich nehme an, das soll in die Entitätsklasse geschrieben werden?
Da kommen bei mir aber nur 2 Fehlermeldungen: 
    1. This method requires a body instead of a semicolon
    2. Query is not an annotation type

Wie kann man also danach suchen?

Ich nutze übrigens EclipseLink.

Ich wäre sehr, sehr dankbar für Hilfe!

Beste Grüße
Tabkas


----------



## httpdigest (16. Okt 2019)

Tabkas hat gesagt.:


> em.find(Tabelle.class, query)


In diesem Fall ist `query` aber keine Query (also javax.persistence.Query) sondern einfach java.lang.Object. Die EntityManager.find(Class, Object) Methode bekommt also die Klasse der zu findenden Entität sowie den Primärschlüssel.



Tabkas hat gesagt.:


> Da kommen bei mir aber nur 2 Fehlermeldungen:
> 1. This method requires a body instead of a semicolon
> 2. Query is not an annotation type


Diese Fehlermeldung hat nichts mit JPA zu tun, sondern damit, dass du syntaktisch ungültigen Java-Code erzeugt hast.



Tabkas hat gesagt.:


> Wie kann man also danach suchen?


Ich würde dir erstmal die Suche nach JPA Tutorials (und Java-Grundlagentutorials) empfehlen. Für ersteres z.B. erstmal: https://www.baeldung.com/jpa-queries


----------



## Tabkas (16. Okt 2019)

Danke für die Antwort.

Bei dem verlinkten Artikel wird ja überall reine SQL Syntax in einen Query gepackt außer bei 
*Criteria API Query*
.
Ist es also das, was du empfiehlst? Denn reine SQL Syntax würde ich eher meiden wollen, dafür wählte ich ja JPA.

Grüße


----------



## mihe7 (16. Okt 2019)

Tabkas hat gesagt.:


> Denn reine SQL Syntax würde ich eher meiden wollen, dafür wählte ich ja JPA.


Was Du siehst, ist kein SQL sondern JPQL, eine an SQL angelehnte Sprache für JPA.


----------



## httpdigest (16. Okt 2019)

Tabkas hat gesagt.:


> Denn reine SQL Syntax würde ich eher meiden wollen, dafür wählte ich ja JPA.


Du kannst ganz getrost JPQL verwenden. JPA spezifiziert diese Sprache und Implementierungen davon enthalten entsprechende Umwandlungen in die Dialekte der verwendeten relationalen SQL-basierten Datenbank. JPA ist ausschließlich für SQL-basierte Datenbanken, somit ist JPQL auch ein durchaus vernünftiger Ansatz, seine Queries zu formulieren.


----------



## Tabkas (17. Okt 2019)

Ich erhalte bei allen Methoden folgenden Fehler:


```
[EL Warning]: 2019-10-17 13:41:47.535--UnitOfWork(1958592872)--Exception [EclipseLink-3002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.ConversionException
Exception Description: The object [false], of class [class java.lang.Boolean], from mapping [org.eclipse.persistence.mappings.DirectToFieldMapping[aktiv-->ANGEBOTE.AKTIV]] with descriptor [RelationalDescriptor(model.Angebote --> [DatabaseTable(ANGEBOTE)])], could not be converted to [class java.lang.Byte].
Exception in thread "main" javax.persistence.PersistenceException: Exception [EclipseLink-3002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.ConversionException
Exception Description: The object [false], of class [class java.lang.Boolean], from mapping [org.eclipse.persistence.mappings.DirectToFieldMapping[aktiv-->ANGEBOTE.AKTIV]] with descriptor [RelationalDescriptor(model.Angebote --> [DatabaseTable(ANGEBOTE)])], could not be converted to [class java.lang.Byte].
    at org.eclipse.persistence.internal.jpa.QueryImpl.getSingleResult(QueryImpl.java:547)
    at org.eclipse.persistence.internal.jpa.EJBQueryImpl.getSingleResult(EJBQueryImpl.java:400)
    at Test.main(Test.java:42)
Caused by: Exception [EclipseLink-3002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.ConversionException
Exception Description: The object [false], of class [class java.lang.Boolean], from mapping [org.eclipse.persistence.mappings.DirectToFieldMapping[aktiv-->ANGEBOTE.AKTIV]] with descriptor [RelationalDescriptor(model.Angebote --> [DatabaseTable(ANGEBOTE)])], could not be converted to [class java.lang.Byte].
    at org.eclipse.persistence.exceptions.ConversionException.couldNotBeConverted(ConversionException.java:75)
    at org.eclipse.persistence.internal.helper.ConversionManager.convertObjectToByte(ConversionManager.java:299)
    at org.eclipse.persistence.internal.helper.ConversionManager.convertObject(ConversionManager.java:126)
    at org.eclipse.persistence.internal.databaseaccess.DatasourcePlatform.convertObject(DatasourcePlatform.java:179)
    at org.eclipse.persistence.mappings.foundation.AbstractDirectMapping.getObjectValue(AbstractDirectMapping.java:620)
    at org.eclipse.persistence.mappings.foundation.AbstractDirectMapping.valueFromRow(AbstractDirectMapping.java:1218)
    at org.eclipse.persistence.mappings.DatabaseMapping.readFromRowIntoObject(DatabaseMapping.java:1512)
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildAttributesIntoObject(ObjectBuilder.java:461)
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:1004)
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildWorkingCopyCloneNormally(ObjectBuilder.java:898)
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObjectInUnitOfWork(ObjectBuilder.java:851)
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:734)
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:688)
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.buildObject(ObjectLevelReadQuery.java:795)
    at org.eclipse.persistence.queries.ReadAllQuery.registerResultInUnitOfWork(ReadAllQuery.java:890)
    at org.eclipse.persistence.queries.ReadAllQuery.executeObjectLevelReadQuery(ReadAllQuery.java:509)
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1168)
    at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:899)
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1127)
    at org.eclipse.persistence.queries.ReadAllQuery.execute(ReadAllQuery.java:403)
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1215)
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2896)
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1804)
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1786)
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1751)
    at org.eclipse.persistence.internal.jpa.QueryImpl.executeReadQuery(QueryImpl.java:258)
    at org.eclipse.persistence.internal.jpa.QueryImpl.getSingleResult(QueryImpl.java:517)
```


Angebote sieht folgendermaßen aus (ohner getter setter  und imports):


```
/**
 * The persistent class for the angebote database table.
 * 
 */
@Entity
@NamedQuery(name="Angebote.findAll", query="SELECT a FROM Angebote a")
public class Angebote implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int angebotsID;

    private byte aktiv;

    private String angebotsURL;

    @Temporal(TemporalType.DATE)
    private Date datum;

    private byte manuellUeberarbeitet;

    private double umsatz;

    private String vertriebskanalAngebotsID;

    //bi-directional many-to-one association to Artikel
    @ManyToOne
    @JoinColumn(name="ArtikelID")
    private Artikel artikel;

    //bi-directional many-to-one association to Vertriebskanaele
    @ManyToOne
    @JoinColumn(name="VertriebskanalID")
    private Vertriebskanaele vertriebskanaele;

    //bi-directional many-to-one association to Lager
    @OneToMany(mappedBy="angebote")
    private List<Lager> lagers;

    //bi-directional many-to-one association to Verkaeufe
    @OneToMany(mappedBy="angebote")
    private List<Verkaeufe> verkaeufes;
```


Die Fehlermeldung sagt, es gäbe einen Konvertierungsfehler von boolesch zu byte. Wo kommt aber boolesch her?

Das Programm zum ausführen ist folgendes Testprogramm:



```
double umsatz = 17.99;
        
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("...");
        EntityManager em = emf.createEntityManager();
        
            CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
            
            CriteriaQuery<Angebote> criteriaQuery = criteriaBuilder.createQuery(Angebote.class);
            
            Root<Angebote> userRoot = criteriaQuery.from(Angebote.class);
            
            Angebote queryResult = em.createQuery(criteriaQuery.select(userRoot)
                                      .where(criteriaBuilder.equal(userRoot.get("umsatz"), umsatz)))
                                      .getSingleResult();
```
 

Ich weiss nicht woher boolean kommt. Ich habe die booleschen Werte als tinyint also als byte in die Tabellen eingetragen:
private byte aktiv; 

Könnt ihr da helfen?

Wenn ihr mehr Infos benötigt sagt bitte Bescheid!

Vielen Dank!!
Grüße


----------



## mrBrown (17. Okt 2019)

Warum nimmst du nicht einfach boolean, wenn du boolean brauchst?
In Java musst du kein Byte nutzen, um booleans darzustellen, das Mapping übernimmt JPA


----------



## Tabkas (17. Okt 2019)

Die Entitätsklassen wurden automatisch mit byte erstellt.

Meinst du, ich sollte die Datentypen in den Entitätsklassen zu boolean ändern?


----------



## Tabkas (17. Okt 2019)

Update:
Ich habe das nun probiert ("Meinst du, ich sollte die Datentypen in den Entitätsklassen zu boolean ändern?").

Es kommt die Fehlermeldung nicht mehr. Nur die Rückgabe ist null. VIelleicht ist der query falsch, ich schaue ab hier mal selber weiter. Bei Problemen die ich nicht selber lösen kann melde ich nochmal 

Vielen Dank soweit!


----------



## Tabkas (17. Okt 2019)

Klappt nun alles, danke euch!


----------

