web-dev-qa-db-de.com

Erstellen einer benutzerdefinierten Abfrage mit Spring DATA JPA?

Ich arbeite an einem Projekt mit Spring Data JPA. Ich habe eine Tabelle in der Datenbank als my_query.

Ich möchte eine Methode erstellen, die eine Zeichenfolge als Parameter verwendet, und sie dann als Abfrage in der Datenbank ausführen.

Methode:

executeMyQuery(queryString)

Als Beispiel, wenn ich bestanden habe 

queryString= "SELECT * FROM my_query"

dann sollte diese Abfrage in der DB-Ebene ausgeführt werden.

Die Repository-Klasse sieht wie folgt aus.

public interface MyQueryRepository extends JpaRepository<MyQuery, Long>{
    public MyQuery findById(long id);

    @Modifying(clearAutomatically = true)
    @Transactional
    @Query(value = "?1", nativeQuery = true)
    public void executeMyQuery(String query);

}

Es funktionierte jedoch nicht wie erwartet. Es gibt den folgenden Fehler.

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''select * from my_query;'' at line 1

Gibt es einen anderen Weg, um dieses Ziel zu erreichen? Danke im Voraus

10
B378

Leider funktioniert Ihr Ansatz nicht. Wenn Sie die Annotation @Query verwenden, geben Sie pro Methode eine korrekte konkrete Abfrage in JPA oder native Notation an.

Der einzige Teil, den Sie parametrieren können, sind Werte, die in der WHERE-Klausel verwendet werden. Betrachten Sie dieses Beispiel aus official doc :

public interface UserRepository extends JpaRepository<User, Long> {
  @Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true)
  User findByEmailAddress(String emailAddress);
}
16
ilya

Danke, @ilya. Gibt es einen alternativen Ansatz, um diese Aufgabe mit Spring Data JPA zu erreichen? Ohne @Query-Anmerkung?

Ich möchte nur auf diesen Teil eingehen. Ja, es gibt einen Weg, wie Sie das Problem lösen können, ohne die @query-Annotation zu verwenden. Sie müssen eine von Ihrer Schnittstelle abgeleitete Abfrage definieren, die die JPA-Repository-Instanz implementiert.

von Ihrer Repository-Instanz aus werden Sie dann allen Methoden zur Verfügung gestellt, die CRUD-Vorgänge in Ihrer Datenbank zulassen, wie z

 interface UserRepository extends CrudRepository<User, Long> {

 long deleteByLastname(String lastname);

 List<User> removeByLastname(String lastname);
}

mit diesen Methoden werden die Daten der Feder verstehen, was Sie zu erreichen versuchen und sie entsprechend umsetzen.

Beachten Sie außerdem, dass die grundlegenden CRUD-Operationen aus der Basisklassendefinition bereitgestellt werden und nicht neu definiert werden müssen. Dies ist beispielsweise die JPARepository-Klasse, wie sie von spring definiert wird. Wenn Sie sie erweitern, erhalten Sie alle Methoden.

 public interface CrudRepository<T, ID extends Serializable>
 extends Repository<T, ID> {

 <S extends T> S save(S entity);      

 Optional<T> findById(ID primaryKey); 

 Iterable<T> findAll();               

 long count();                        

 void delete(T entity);               

 boolean existsById(ID primaryKey);   


}

Weitere aktuelle Informationen finden Sie in der Dokumentation unter https://docs.spring.io/spring-data/jpa/docs/current/reference/html/

1
Austine Gwa

Dafür gibt es keine besondere Unterstützung. Sie können jedoch eine benutzerdefinierte Methode mit einem String-Parameter erstellen. In Ihrer Implementierung wird die EntityManager-Instanz eingefügt und ausgeführt.

Möglicherweise hilfreiche Links:

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-implementations

Zugriff auf Entity Manager mit Spring Boot- und Spring-Daten

Hinweis: Ich würde es noch einmal überdenken, ob das, was Sie versuchen, eine gute Idee ist, weil die Implementierungsdetails des Repositorys in den Rest der Anwendung eingeblendet werden.

1
Jens Schauder

Mit EntityManager können Sie dies erreichen.

Angenommen, Ihre Entitätsklasse ist wie folgt:

import javax.persistence.*;
import Java.math.BigDecimal;

@Entity
@Table(name = "USER_INFO_TEST")
public class UserInfoTest {
    private int id;
    private String name;
    private String rollNo;

    public UserInfoTest() {
    }

    public UserInfoTest(int id, String name) {
    this.id = id;
    this.name = name;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID", nullable = false, precision = 0)
    public int getId() {
        return id;
    }

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

    @Basic
    @Column(name = "name", nullable = true)
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Basic
    @Column(name = "roll_no", nullable = true)
    public String getRollNo() {
        return rollNo;
    }

    public void setRollNo(String rollNo) {
        this.rollNo = rollNo;
    }
}

Und Ihre Abfrage lautet "select id, Name von Benutzern mit roll_no = 1001".

Hier gibt die Abfrage ein Objekt mit der ID und einer Namensspalte zurück. Ihre Antwortklasse ist wie folgt:

Ihre Antwortklasse ist wie folgt:

public class UserObject{
    int id;
    String name;
    String rollNo;

    public UserObject(Object[] columns) {
        this.id = (columns[0] != null)?((BigDecimal)columns[0]).intValue():0;
        this.name = (String) columns[1];
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getRollNo() {
        return rollNo;
    }

    public void setRollNo(String rollNo) {
        this.rollNo = rollNo;
    }
}

hier erhält der UserObject-Konstruktor ein Objekt-Array und setzt Daten mit dem Objekt.

public UserObject(Object[] columns) {
            this.id = (columns[0] != null)?((BigDecimal)columns[0]).intValue():0;
            this.name = (String) columns[1];
        }

Ihre Abfrageausführungsfunktion ist wie folgt:

public UserObject getUserByRoll(EntityManager entityManager,String rollNo) {

        String queryStr = "select id,name from users where roll_no = ?1";
        try {
            Query query = entityManager.createNativeQuery(queryStr);
            query.setParameter(1, rollNo);

            return new UserObject((Object[]) query.getSingleResult());
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }

Hier müssen Sie folgende Pakete importieren:

import javax.persistence.Query;
import javax.persistence.EntityManager;

Jetzt müssen Sie diese Funktion in Ihrer Hauptklasse aufrufen. Holen Sie sich zuerst EntityManager und rufen Sie die Funktion getUserByRoll(EntityManager entityManager,String rollNo) auf. Das Aufrufverfahren ist unten angegeben:

Hier sind die Importe

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

EntityManager von diesem Weg erhalten:

@PersistenceContext
private EntityManager entityManager;

UserObject userObject = getUserByRoll(entityManager,"1001");

Jetzt haben Sie Daten in diesem userObject.

Hinweis:

query.getSingleResult() gibt ein Objektarray zurück. Sie müssen die Spaltenposition und den Datentyp mit der Abfragespaltenposition pflegen.

ID auswählen, Name von Benutzern, bei denen roll_no = 1001 

abfrage gibt ein Array zurück und es ist [0] -> id und 1 -> name.

Mehr Infos unter diesem Thread .

0

Basierend auf @jelies answer verwende ich den folgenden Ansatz

Sie können eine andere Schnittstelle für Ihre benutzerdefinierten Methoden erstellen (als Beispiel MyQueryCustom) und diese dann wie folgt implementieren.

public class MyQueryRepositoryImpl implements MyQueryRepositoryCustom {
    @PersistenceContext
    private EntityManager entityManager;

    public int executeQuery(String query) {
        return entityManager.createNativeQuery(query).executeUpdate();
    }
}

Dadurch wird eine benutzerdefinierte Abfrage ausgeführt.

0
B378