Custom query in spring boot JPA using postgres db - postgresql

I am connecting my spring boot application to postgres db, i am able insert values using JPA. Now i want to retrieve data from the table. I would like to use the #Query from JPA to select the column in the table. while i run the application i get sql error. Here is the repository code
#Query(value = "SELECT user.firstname AS firstName, user.lastName AS lastName FROM user_details user WHERE emailid LIKE ?1", nativeQuery = true)
EmailOnly findUserByEmail(String emailId);
public static interface EmailOnly {
String getFirstName();
String getLastName();
}
Entity class
#Getter
#Setter
#Entity
#Table(name = "USER_DETAILS")
public class UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private int userId;
private String emailId;
private String firstName;
private String lastName;
}
I get error as
SQL Error: 0, SQLState: 42601 2020-03-23 17:04:05.128 ERROR 27508 ---
[nio-8080-exec-2] o.h.engine.jdbc.spi.SqlExceptionHelper : ERROR:
syntax error at or near "."
All the example in jpa shows to select data using aliases, but its now working for me. If i try to remove all the aliases from the query i am getting the projection values as null.

Related

Spring Data: Fetching values from Entity with #ElementCollection

My Entity class is:
#Entity
#Data
#Table(uniqueConstraints = { #UniqueConstraint(columnNames = {"username" }, name = "uq_username") } })
public class User{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#NotNull
private String firstName;
private String lastName;
#ElementCollection(targetClass = Role.class,fetch = FetchType.LAZY)
#JoinTable(name = "User_Roles", joinColumns={#JoinColumn(name = "user_id")})
#Enumerated(EnumType.STRING)
private List<Role> roles;
}
Role class is an enumeration:
public enum Role {
ADMIN,
OFFICE_USER,
SUPERVISOR,
MANAGER,
DATA_ENTRY
}
Property spring.jpa.hibernate.ddl-auto=create and the tables user and user_roles (fields: user_id, roles) are created and data inserted successfully. However, querying for data for users with a role is not working. My repository is:
#Component
public interface UserRepository extends CrudRepository<User, Integer>, JpaRepository<User, Integer> {
#Query(value = "select usr from User usr where usr.firstName LIKE :username% OR usr.lastName LIKE :username%"
+ " AND usr.roles=:roles")
public List<User> fetchUsersByNameAndRole(String username, Collection<String> roles);
}
On passing the following request I am getting error
http://localhost:8080/api/users/search/fetchUsernamesByNameAndRole?username=Thom&roles=SUPERVISOR
[org.springframework.data.rest.webmvc.ResourceNotFoundException: EntityRepresentationModel not found!]
If I change Repository method (changing username parameter to String from Collection) to
#Query(value = "select usr from User usr where usr.firstName LIKE :username% OR usr.lastName LIKE :username%"
+ " AND usr.roles=:roles")
public List<User> fetchUsersByNameAndRole(String username, String roles);
The error becomes:
[org.springframework.dao.InvalidDataAccessApiUsageException: Parameter value [SUPERVISOR] did not match expected type [java.util.Collection (n/a)]; nested exception is java.lang.IllegalArgumentException: Parameter value [SUPERVISOR] did not match expected type [java.util.Collection (n/a)]]
Question 1: How can I fetch all users with a name and a particular role (or set of roles) in this scenario?
The code is working if I remove the roles clause, like
#Query(value = "select usr from User usr where usr.firstName LIKE :username% OR usr.lastName LIKE :username%")
public List<User> fetchUsersByName(String username);
I need the user names only. So I changed code to:
#Query(value = "select usr.firstName from User usr where usr.firstName LIKE :username% OR usr.lastName LIKE :username%")
public List<String> fetchUsersByName(String username);
But gets the error:
org.springframework.data.mapping.MappingException: Couldn't find PersistentEntity for type class java.lang.String
Changing to native query also gives same error:
#Query(value ="select first_name from user where first_name like ?1%", nativeQuery = true)
Question 2: Why mapping to List is not working in Spring data? I remember it was working with normal Spring JPA

unable to get table from postgreSQL despite the spring boot program being connected to database and the database not being empty

I am rather new to Spring boot and I am trying to write a very simple program that can perform post, get and delete on a postgreSQL data base. the database is named "recipes" schema "public" and table "recipe"
The problem that I ran into is that when I make the get request through postman, it simply returns null despite the data base being initialized with data.
like so
I did my best to try and narrow down the problem and the furthest I got is that line from the service layer is returning nothing when evaluated
jdbcTemplate.query(sql, new RecipeRowMapper())
The database is initialized with the following SQL
INSERT INTO recipe(id, name, ingredients, instructions, date_added)
values (1, 'ini test1', '10 cows 20 rabbits', 'cook ingredients with salt', '2004-01-02'),
(2, 'ini test2', '30 apples 20 pears', 'peel then boil', '2004-01-13');
I know the database is not empty because when I run the following SQL
SELECT * from recipe
i get
And the data base is connected as seen below (one thing I do find strange is that the table "recipe" isn't showing up in the DB browser but I don't know what to make of it)
application.yml
app:
datasource:
main:
driver-class-name: org.postgresql.Driver
jdbc-url: jdbc:postgresql://localhost:5432/recipes?currentSchema=public
username: postgres
password: password
server:
error:
include-binding-errors: always
include-message: always
spring.jpa:
database: POSTGRESQL
hibernate.ddl-auto: create
show-sql: true
dialect: org.hibernate.dialect.PostgreSQL9Dialect
format_sql: true
spring.flyway:
baseline-on-migrate: true
this is the service layer
public List<Recipe> getRecipes(){
var sql = """
SELECT id, name, ingredients, instructions, date_added
FROM public.recipe
LIMIT 50
""";
return jdbcTemplate.query(sql, new RecipeRowMapper());
}
and this is the controller
#GetMapping(path = "/test")
public String testRecipe(){
return recipeService.test();
}
and rowmapper
public class RecipeRowMapper implements RowMapper<Recipe> {
#Override
public Recipe mapRow(ResultSet rs, int rowNum) throws SQLException {
return new Recipe(
rs.getLong("id"),
rs.getString("name"),
rs.getString("ingredients"),
rs.getString("instructions"),
LocalDate.parse(rs.getString("date_added"))
);
}
}
finally recipe entity looks like this
#Data
#Entity
#Table
public class Recipe {
#Id
#GeneratedValue(
strategy = GenerationType.IDENTITY
)
#Column(name = "id", updatable = false, nullable = false)
private long id;
#Column(name = "name")
private String name;
#Column(name = "ingredients")
private String ingredients;
#Column(name = "instructions")
private String instructions;
#Column(name = "date_added")
private LocalDate dateAdded;
public Recipe(){};
public Recipe(long id, String name, String ingredients, String instructions, LocalDate date){}
public Recipe(String name,
String ingredients,
String instructions,
LocalDate dateAdded
) {
this.name = name;
this.ingredients = ingredients;
this.instructions = instructions;
this.dateAdded = dateAdded;
}
}
As it turns out the problem is caused by the LocalDate not being converted correctly and was being posted as null. That caused the
LocalDate.parse(rs.getString("date_added"))
to throw a null pointer exception which is what has been causing all the problems...

Hibernate #Column annotation cannot mapping to database

I have a Entity in Spring Boot and PostgreSql, I'm using #Column annotation to mapping to database. This is my Entity snip code :
#Entity(name = "users")
#Table(name = "users", schema = "public")
public class User implements Serializable {
/**
*
*/
private static final long serialVersionUID = 12355345L;
#Id
#Column(name = "user_id")
private String userid;
#Column(name = "user_name")
private Integer username;
When id run and test with postman, i get an error :
org.springframework.dao.InvalidDataAccessResourceUsageException: could
not extract ResultSet; SQL [n/a]; nested exception is
org.hibernate.exception.SQLGrammarException: could not extract
ResultSet
Caused by: org.postgresql.util.PSQLException: ERROR: column users0_.usersid does not exist
Hint: Perhaps you meant to reference the column "users0_.user_id".
I don't know why. How to resolve this ?
There are couple of things for your info.
1) Need to check your spring.jpa.hibernate.ddl-auto property as depends on that property, the database tables, columns will be populated by Hibernate.
2) Next drop the existing table and change the value as spring.jpa.hibernate.hbm2ddl.auto=update so that it will create/update table according to the annotations provided in the entity class
3) Remove unnecessary annotations. Following is enough.
#Entity
#Table(name = "users")
public class User implements Serializable {
#Id
#Column(name = "user_id")
private String userid;
................

Spring data jpa JOIN does't work in #Query

I am using spring-data-jpa. I wrote a native query but it doesn't work. Here is my entity classes:
#Entity
#Table(name="view_version")
public class ViewVersionDom {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name="view_id")
private ViewDom view;
private Integer version;
#ManyToOne
#JoinColumn(name="datasource_param_id")
private DatasourceParamDom datasourceParam;
private String description;
#Column(name="created_date")
private Date createdDate;
#Entity
#Table(name="view_permission")
public class ViewPermissionDom extends BaseDom {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name="view_id")
private ViewDom view;
#ManyToOne
#JoinColumn(name="user_id")
private UserDom user;
#ManyToOne
#JoinColumn(name="group_id")
private GroupDom group;
private Boolean read;
private Boolean write;
private Boolean execute;
Here is the query:
#Query(value = " SELECT v FROM ViewVersionDom v LEFT JOIN ViewPermissionDom vp ON v.view.id = vp.id "
+ " where (v.view.user.id = ?1 OR (vp.read=true and (vp.user.id=?1 or vp.user.id is NULL and vp.group.id is NULL or vp.group.id in (?2)))) "
+ " ORDER BY v.view.name", nativeQuery=true)
public List<ViewVersionDom> findUserViews(Long userId, List<Long> groupIds);
At first when I didn't write nativeQuery=true the application didn't build and I got an exception 'path expected for join jpa'. When I set the settings nativeQuery=true the application is started, but when I call the function I got the following error:
org.hibernate.engine.jdbc.spi.SqlExceptionHelper - [ERROR: relation "viewversiondom" does not exist Position: 16]
org.hibernate.exception.SQLGrammarException: could not extract ResultSet]
Does there any other settings or annotation that will resolve the problem?
I have searched in google, but in all cases 2 tables connected with each other directly.
Your query is not a SQL query (assuming, you don't have a column v in one for your tables).
Also the Table viewversiondom doesn't exist or is not accessible to the database user used for the connection.
Also when mapping native queries to domain objects you should have a look at https://jira.spring.io/browse/DATAJPA-980

JPA failed to automatically generate a table from an entity

I am using Eclipselink with Derby database to automatically generated a database from Entities.
The generation worked just fine at first, but when i added a User entity to my model and tried to generate tables from entities with JPA tools all the tables are generated except the User table & i get the following error during the generation
[EL Warning]: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.1.v20150605-31e8258): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLSyntaxErrorException: Syntax error: Encountered "USER" at line 1, column 14.
Error Code: 30000
This is the user entity
#NamedQuery( name = "User.findByUsername", query = "SELECT u FROM User u WHERE u.username = :userneme AND u.password = :password" )
#Entity
public class User implements Serializable {
#Transient
private static final long serialVersionUID = 1L;
public User() {
super();
}
#Id
#GeneratedValue( strategy = GenerationType.AUTO )
private Integer id;
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername( String username ) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword( String password ) {
this.password = password;
}
Can anyone tell me why i am getting the exception ?
Thanks in advance
Your table name is "USER" which is a reserved keyword in SQL (and in Apache Derby). Some JPA providers (e.g DataNucleus JPA) automatically quote such keywords for you meaning it would just work. Others (e.g EclipseLink) don't and so you have to explicitly set the table name with surrounding quote marks (') or set the table name to something that is not a SQL keyword
#Table(name="'User'")
public class User {...}
This most likely is because USER is a function in the Derby Database (Refer this : http://db.apache.org/derby/docs/10.10/ref/rrefsqlj42476.html). You possibly can have the JPA bean as User , but specify a different table name using #Table annotation