how to write jpa query? in repository - spring-boot

enter image description here
this img is user table and example tuple
here,
I want to use sql query "SELECT MAX(KEY_NAME) FROM USER;" and right here
enter image description here
So in java, I wrote jpa query but I met ERROR 16148
2023-02-01 20:58:51.668 ERROR 16148 --- [nio-8080-exec-7] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: Type specified for TypedQuery [gdsc.toypj.dutchpayit.domain.User] is incompatible with query return type [class java.lang.Long]; nested exception is java.lang.IllegalArgumentException: Type specified for TypedQuery [gdsc.toypj.dutchpayit.domain.User] is incompatible with query return type [class java.lang.Long]] with root cause
here my source
UserRepository.java
public User findOneUser() {
return em.createQuery("select MAX(r.id) from User r", User.class)
.getSingleResult();
}
User.java
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "key_name")
private Long id;
private String name;
#OneToMany(mappedBy = "user",cascade = CascadeType.ALL)
private List<Menu> menuList = new ArrayList<>();
#OneToMany(mappedBy = "user",cascade = CascadeType.ALL)
private List<People> peopleList = new ArrayList<>();
public static User addUser(String name){
User user = new User();
user.setName(name);
return user;
}
UserService.java
#Transactional
public User OneUser(){
User user = userRepository.findOneUser();
return user;
}
UserController.java
#GetMapping("/get/one")
public ResponseEntity getOneUser(){
User user = userService.OneUser();
return ResponseEntity.status(HttpStatus.OK).body(new SuccessResponse(200,user));
}
I've been trying more than 3 hours..
in UserRepository.java, I tried them and error in everything.
em.createQuery("select MAX(r.Key_name) from User r", User.class)
em.createQuery("select id from User", User.class)
oh this is worked
return em.createQuery("select r from User r", User.class)
.getResultList();
why only "select r" is working I don't know!!!!

The error comes from the TypedQuery defined to return the User object.
You can try and change the TypedQuery to Long or create another query that will return the User as an object.
You can go with something similar like this:
select r from User r where r.id = (select MAX(r.id) from User r)

Related

Could not create query for public Spring JPA

I have two classes Employee and Asset. they have a relationship #ManyToOne.
When I try to left join tables console shows a runtime error.
Please
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'assetController' defined in file [C:\Users\User\Desktop\material-assets\target\classes\com\alsecotask\materialassets\controller\AssetController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'assetService' defined in file [C:\Users\User\Desktop\material-assets\target\classes\com\alsecotask\materialassets\service\AssetService.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'assetRepository' defined in com.alsecotask.materialassets.repository.AssetRepository defined in #EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Invocation of init method failed; nested exception is org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract java.util.List com.alsecotask.materialassets.repository.AssetRepository.getAssetsByEmployee()! Reason: Validation failed for query for method public abstract java.util.List com.alsecotask.materialassets.repository.AssetRepository.getAssetsByEmployee()!; nested exception is java.lang.IllegalArgumentException: Validation failed for query for method public abstract java.util.List com.alsecotask.materialassets.repository.AssetRepository.getAssetsByEmployee()!
AssetReposiory where I wrote my query
public interface AssetRepository extends JpaRepository<Asset, Long> {
Long countAssetByEmployee_Id(Long id);
#Query("SELECT Employee.id, Employee.firstName, sum(Asset .price), count(Asset .price)\n" +
"FROM Asset \n" +
" LEFT JOIN Employee \n" +
" ON Employee .id = Asset .employee.id group by Employee .id\n")
List<?> getAssetsByEmployee();
#Query(value = "SELECT * FROM Asset WHERE name = ?1", nativeQuery = true)
Asset findByNameQuery(String name);
}
Asset class
public class Asset {
#Id
#GeneratedValue
private Long id;
private String name;
private double price;
#ManyToOne
#JoinColumn(name = "employee_id", nullable = false)
private Employee employee;}
Employee class
public class Employee {
#Id
#SequenceGenerator(
name = "employee_sequence",
sequenceName = "employee_sequence",
allocationSize = 1
)
#GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "employee_sequence"
)
private Long id;
private String firstName;
private String lastName;
public Employee(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
]
Change the return type as List<Object[]>.
#Query(value="SELECT Employee.id, Employee.firstName, sum(Asset
.price), count(Asset .price)\n" +
"FROM Asset \n" +
" LEFT JOIN Employee \n" +
" ON Employee .id = Asset .employee.id group by
Employee.id\n", nativeQuery= true)
List<Object[]> getAssetsByEmployee();

how to get data from manyToMany entities

I have two entities user and movie. I want to display movies for the users. Users are going to see the movies they added. I connected these two enetities with manyToMany and i am trying to get the data but i am having this error.
2021-05-27 01:01:16.109 ERROR 4064 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.QueryException: could not resolve property: user of: com.moviePage.movieP.Entities.Movie [from com.moviePage.movieP.Entities.Movie m join m.user u where u.id = 1]; nested exception is java.lang.IllegalArgumentException: org.hibernate.QueryException: could not resolve property: user of: com.moviePage.movieP.Entities.Movie [from com.moviePage.movieP.Entities.Movie m join m.user u where u.id = 1]] with root cause
org.hibernate.QueryException: could not resolve property: user of: com.moviePage.movieP.Entities.Movie
at org.hibernate.persister.entity.AbstractPropertyMapping.propertyException(AbstractPropertyMapping.java:77) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.hibernate.persister.entity.AbstractPropertyMapping.toType(AbstractPropertyMapping.java:71) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.toType(AbstractEntityPersister.java:2038) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.hibernate.hql.internal.ast.tree.FromElementType.getPropertyType(FromElementType.java:412) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.hibernate.hql.internal.ast.tree.FromElement.getPropertyType(FromElement.java:520) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.hibernate.hql.internal.ast.tree.DotNode.getDataType(DotNode.java:695) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.hibernate.hql.internal.ast.tree.DotNode.prepareLhs(DotNode.java:269) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.hibernate.hql.internal.ast.tree.DotNode.resolve(DotNode.java:209) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.hibernate.hql.internal.ast.tree.FromReferenceNode.resolve(FromReferenceNode.java:114) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
at org.hibernate.hql.internal.ast.tree.FromReferenceNode.resolve(FromReferenceNode.java:109) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
...
User
#Entity
#Table(name="user")
public class User {
#Id
#Column(name="user_id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
#NotNull(message="Enter first name")
#Column(name="name")
private String name;
#ManyToMany
#JoinTable(
name="user_movie",
joinColumns =#JoinColumn(name="user_id"),
inverseJoinColumns=#JoinColumn(name="movie_id"))
private Set<Movie> movies;
Movie
#Entity
#Table(name="movie")
public class Movie {
#Id
#Column(name="movie_id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
#Column(name="title")
private String title;
#Lob
#Column(name="summary")
private String summary;
#ManyToMany(mappedBy = "movies")
private Set<User> users;
getMovies => i put this in data access layer and call it from the controller and from the controller i am going to send the movies to the html page
public List<Movie> getMovies(int id) {
Session session = entityManager.unwrap(Session.class);
String hql = "from Movie m join m.user u where u.id = "+ String.valueOf(id);
List<Movie> movies = session.createQuery(hql).list();
System.out.println(movies);//tried to look what it will return
return movies;
}
//List<Movie> movies = session.createQuery("from Movie m join m.user u where u.user_id=:user_id").setParameter("id", id).getResultList();
i have tried these two and both produce the same error. I couldn't understand the error please help:)
You probably want:
String hql = "from Movie m join m.users u where u.id = "+ String.valueOf(id);

Select a unique names from Users that have more than 3 Articles. Spring Data, H2

I use: Spring Boot, Spring Data, and H2 (in-memory) DataBase.
DB TABLES:
CREATE TABLE user
(
id INT AUTO_INCREMENT,
name VARCHAR(250) NOT NULL,
age INT NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE article
(
id INT AUTO_INCREMENT,
text TEXT NOT NULL,
color ENUM ('red', 'green', 'blue', 'yellow', 'pink') NOT NULL,
user_id INT,
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE ON UPDATE CASCADE
);
In ArticleRepository exploited such query:
SELECT u.name, a.user_id, count() FROM user AS u INNER JOIN article AS a ON u.id = a.user_id GROUP BY a.user_id HAVING COUNT() > 3;
#Repository
public interface ArticleRepository extends JpaRepository<Article, Integer> {
#Query(value = "SELECT u.name, a.user_id, count(*) FROM user AS u INNER JOIN article AS a ON u.id = a.user_id GROUP BY a.user_id HAVING COUNT(*) > 3", nativeQuery = true)
List<Article> findUserNamesByArticlesCountMoreThan();
}
After request I receive the error:
In Postman:
"error": "Internal Server Error", "message": "could not execute query;
SQL [SELECT u.name, a.user_id, count(text) FROM user AS u INNER JOIN
article AS a ON u.id = a.user_id GROUP BY a.user_id HAVING COUNT(*) >
3]; nested exception is org.hibernate.exception.SQLGrammarException:
could not execute query",
In IntelliJ Idea:
02:54:24.681 [http-nio-9090-exec-1] WARN SqlExceptionHelper - SQL
Error: 42122, SQLState: 42S22 02:54:24.681 [http-nio-9090-exec-1]
ERROR SqlExceptionHelper - Column "id" not found [42122-197]
02:54:24.703 [http-nio-9090-exec-1] ERROR [dispatcherServlet] -
Servlet.service() for servlet [dispatcherServlet] in context with path
[] threw exception [Request processing failed; nested exception is
org.springframework.dao.InvalidDataAccessResourceUsageException: could
not execute query; SQL [SELECT u.name, a.user_id, count(text) FROM
user AS u INNER JOIN article AS a ON u.id = a.user_id GROUP BY
a.user_id HAVING COUNT(*) > 3]; nested exception is
org.hibernate.exception.SQLGrammarException: could not execute query]
with root cause org.h2.jdbc.JdbcSQLException: Column "id" not found
[42122-197] at
org.h2.message.DbException.getJdbcSQLException(DbException.java:357)
at org.h2.message.DbException.get(DbException.java:179) at
org.h2.message.DbException.get(DbException.java:155) at
org.h2.jdbc.JdbcResultSet.getColumnIndex(JdbcResultSet.java:3148) at
org.h2.jdbc.JdbcResultSet.get(JdbcResultSet.java:3247) at
org.h2.jdbc.JdbcResultSet.getInt(JdbcResultSet.java:346)..............
Help me to resolve this problem, and find a mistake.
Entities:
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
#Table(name = "article")
public class Article {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private Integer id;
#Column(name = "text", nullable = false)
private String text;
#Column(name = "color", nullable = false, unique = true)
#Enumerated(EnumType.STRING)
private Color color;
#JsonIgnore
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL )
#JoinColumn(name = "user_id", referencedColumnName="id")
private User user;
}
.
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
#ToString(exclude = "articles")
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Integer id;
#Column(name = "name", nullable = false)
private String name;
#Column(name = "age", nullable = false)
private Integer age;
#JsonIgnore
#OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
private Set<Article> articles;
}
Service:
#Service
public class ArticleService {
private ArticleRepository articleRepository;
#Autowired
public ArticleService(ArticleRepository articleRepository) {
this.articleRepository = articleRepository;
}
public List<Article> findAllUserNamesByArticlesMoreThan() {
return articleRepository.findUserNamesByArticlesCountMoreThan(); }}
ArticleDtoService:
#Service
public class ArticleDtoService {
private ArticleService articleService;
#Autowired
public ArticleDtoService(ArticleService articleService) {
this.articleService = articleService;
}
public ResponseEntity<List<ArticleDto>> getAllUserNamesByArticlesMoreThan() {
List<Article> articles = articleService.findAllUserNamesByArticlesMoreThan();
Link link = linkTo(methodOn(ArticleController.class).getAllUserNamesListByArticlesMoreThan()).withSelfRel();
return new ResponseEntity<>(createArticleDtoList(articles, link), HttpStatus.OK); }}
ArticleController:
#RestController
public class ArticleController {
private final ArticleDtoService articleDtoService;
#Autowired
public ArticleController(ArticleDtoService articleDtoService) {
this.articleDtoService = articleDtoService;
}
#GetMapping(value = "/api/articles/count")
public ResponseEntity<List<ArticleDto>> getAllUserNamesListByArticlesMoreThan() {
return articleDtoService.getAllUserNamesByArticlesMoreThan(); }}
ArticleDto:
public class ArticleDto extends ResourceSupport {
public Article article;
public ArticleDto(Article article, Link selfLink) {
this.article = article;
add(selfLink); }}

Eager fetch property in Mapped Super class

Our Mapped Super class has createdBy column which is defined to be lazily loaded
#MappedSuperclass
#EntityListeners(AuditingEntityListener.class)
#XmlAccessorType(XmlAccessType.FIELD)
public abstract class AbstractAuditingEntity implements Serializable {
#CreatedBy
#ManyToOne(fetch = FetchType.LAZY)
#XmlTransient
#JoinColumn(name = "created_by", updatable = false, columnDefinition = "bigint")
protected User createdBy;
public User getCreatedBy() {
return createdBy;
}
public void setCreatedBy(User createdBy) {
this.createdBy = createdBy;
}
I need to load this property eagerly in one of the sub class that inherits this aforementioned class.
#Override
#XmlElement(name = "createdBy")
#JsonProperty("createdBy")
public User getCreatedBy() {
return super.getCreatedBy();
}
How can I do that?
I tried the following (used NamedEntityGraph and HQL), but, both did not return createdBy from MappedSuperClass that is defined as lazy
//defined at the top of Model
#NamedEntityGraphs({
// eagerly fetches created by and program names when used
#NamedEntityGraph(
name = "graphWithCreatedBy",
attributeNodes = {
#NamedAttributeNode("createdBy")
}
)
})
//Repository method
#EntityGraph(value = "Program.createdBy", type = EntityGraph.EntityGraphType.FETCH) //tried both LOAD and FETCH
Program findOne(Specification<Program> specification);
---Using HQL FETCH JOIN --
//Repository Implementation
private static final String PROGRAM_USER_QUERY = "SELECT " +
" sp FROM Program sp " +
" LEFT JOIN FETCH sp.createdBy where sp.id = :id";
Query query = entityManager.createQuery(PROGRAM_USER_QUERY ).
setParameter("id", id);
query.getSingleResult();
Both approaches returns program, but not the createdBy User
What am I doing wrong?

Hibernate: ManyToMany inverse Delete

I have a ManyToMany relationship between two tables, User and Keyword. The User is the owner of the relationship. If I delete a User, I remove first all Keywords from this User and then delete the User. This works as expected.
But I don't know how to delete a Keyword and automatically delete the relations to all Users.
Here is my code so far.
#Entity
#Table(name = "user")
public class User {
#Id
#Column(name = "id")
#GeneratedValue
private Integer id;
#Column(name = "name")
private String name;
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#Fetch(value = FetchMode.SUBSELECT)
#JoinTable(name = "user_has_keyword", joinColumns = #JoinColumn(name = "user_id"), inverseJoinColumns = #JoinColumn(name = "keyword_id"))
private List keywords = new ArrayList();
// Getters and setters
...
}
#Entity
#Table(name = "keyword")
public class Keyword {
#Id
#Column(name = "id")
#GeneratedValue
private Integer id;
#Column(name = "keyword")
private String keyword;
#ManyToMany(mappedBy = "keywords")
private List users = new ArrayList();
// Getters and setters
...
}
#Service("myService")
#Transactional("transactionManager")
public class MyService {
#Resource(name = "sessionFactory")
private SessionFactory sessionFactory;
#SuppressWarnings("unchecked")
public List getAllUsers() {
Session session = this.sessionFactory.getCurrentSession();
Query query = session.createQuery("FROM User");
return query.list();
}
public User getUser(Integer id) {
Session session = this.sessionFactory.getCurrentSession();
return (User) session.get(User.class, id);
}
public void addUser(User user) {
Session session = this.sessionFactory.getCurrentSession();
session.save(user);
}
public void deleteUser(User user) {
Session session = this.sessionFactory.getCurrentSession();
// 1st, delete relations
user.getKeywords().clear();
session.update(user);
// 2nd, delete User object
session.delete(user);
}
public Keyword getKeyword(Integer id) {
Session session = this.sessionFactory.getCurrentSession();
return (Keyword) session.get(Keyword.class, id);
}
public Keyword addKeyword(Keyword keyword) {
Session session = this.sessionFactory.getCurrentSession();
session.save(keyword);
return keyword;
}
public void deleteKeyword(Keyword keyword) {
Session session = this.sessionFactory.getCurrentSession();
// 1st, delete relations
keyword.getUsers().clear();
session.update(keyword);
// 2nd, delete User object
keyword = getKeyword(keyword.getId());
session.delete(keyword);
}
}
#Controller
public class MyController {
#Resource(name = "myService")
private MyService myService;
#RequestMapping(value = "/add", method = RequestMethod.GET)
public String add(Model model) {
Keyword k = new Keyword();
k.setKeyword("yellow");
k = myService.addKeyword(k);
User u1 = new User();
u1.setName("Bart");
u1.getKeywords().add(k);
myService.addUser(u1);
User u2 = new User();
u2.setName("Lisa");
u2.getKeywords().add(k);
myService.addUser(u2);
return "/";
}
#RequestMapping(value = "/delete/user", method = RequestMethod.GET)
public String deleteUser(Model model) {
User u = myService.getUser(1);
myService.deleteUser(u);
return "/";
}
#RequestMapping(value = "/delete/keyword", method = RequestMethod.GET)
public String deleteKeyword(Model model) {
Keyword k = myService.getKeyword(1);
myService.deleteKeyword(k);
return "/";
}
}
If I browse to /delete/keyword I get the following exception:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.blabla.prototype.Keyword.users, no session or session was closed
I've googled and tried many different things, but nothing works.
I appreciate any help.
Thank you very much,
Marco
The LazyInitializationException has nothing to do with deletion. You're loading a Keyword in your controller. This makes the service load the keyword, without initializing its lazy list of users. This keyword is then returned to the controller, and the transaction is committed, and the session is closed, making the keyword detached from the session.
Then you pass this detached keyword to the service to delete it. The service thus receives a detached keyword, and tries to access its list of users. Since the keyword is detached and the list of users hasn't been loaded yet, this causes a LazyInitializationException.
The service method should take the ID of the keyword to delete as argument, load it, and thus work with an attached keyword, and then proceed with the deletion.
Now to answer your question, you got it right for the user deletion: you remove all the keywords from the user to delete, because the user is the owner of the association. Apply the same logic when deleting a keyword : remove the keyword from all the users referencing it, and delete the keyword:
public void deleteKeyword(Integer id) {
Keyword keyword = getKeyword(id);
for (User user : keyword.getUsers()) {
user.removeKeyword(keyword);
}
session.delete(keyword);
}
Note that you don't have to call update() when working with attached entities. The state of attached entities is automatically and transparently saved to the database.

Resources