In spring, JPA, i want to extend my User model into More more User types.
And i like it to be in a single table.
i believe i did my example right, but some how i am getting null for the findOne method
can you help my please, i can't figure out what is wrong
here is my code (I have more users types, but the basic is not working):
User:
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="user_type")
public abstract class User {
public LicenseType license = LicenseType.FREE;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
public Long id;
public String username;
public String password;
#OneToOne(fetch = FetchType.LAZY)
public Country country;
#OneToOne(fetch = FetchType.LAZY)
public UserPhoto profilePhoto;
....
....
}
UserBasic
#Entity
#DiscriminatorValue("UserBasic")
public class UserBasic extends User {
}
UserRepository
#NoRepositoryBean
public interface UserRepository<T extends User> extends Repository<T, Long>{
T findOne(Long id);
T findByFacebookId(Long facebookId);
}
UserBasicRepository
public interface UserBasicRepository extends UserRepository<UserBasic>{
#Modifying
#Query(value="UPDATE User SET someField = now() WHERE id = ?1", nativeQuery= true)
long updateSomeField(Long userId);
}
UserService
public class UserServiceImpl implements UserService {
#Autowired
private UserBasicRepository userBasicRepository;
#Override
public User findOne(Long userId) {
/**
*
* THIS WILL RETURN NULL
* vv
*
*/
return userBasicRepository.findOne(userId);
}
....
....
}
QUESTION UPDATE
now after the comment, i printed the query and i think i see the problem
and userbasic0_.user_type='UserBasic'
i just wanted inheritance, didn't ask for extra comment. how can i remove this condition.
Hibernate:
select
userbasic0_.id as id2_8_0_,
userbasic0_.password as passwor12_8_0_,
userbasic0_.username as usernam15_8_0_,
.....
from
User userbasic0_
where
userbasic0_.id=?
and userbasic0_.user_type='UserBasic'
Related
My problem is when I try to make a customized query, I want to use crud or jpa repositories for my repository to make custom methods to do the following operations on the database, but I can't succeed in any way...
CartRepository
package com.example.registrationlogindemo.repository;
import com.example.registrationlogindemo.model.Cart;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
public interface CartRepository extends CrudRepository<Cart,Long> {
#Query(name = "INSERT INTO cart VALUES (:productID,:userID)",nativeQuery = true)
List<Cart> save(#Param("productID") Long productId, #Param("userID") Long userID);
#Query(name = "SELECT * FROM cart WHERE user_id = ?2",nativeQuery = true)
List<Cart>showAll(Long productID, Long userID);
}
Cart
package com.example.registrationlogindemo.model;
import jakarta.persistence.*;
import lombok.*;
#Data
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "cart")
public class Cart {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}
Controller
#Controller
public class CartController {
private static SessionFactory factory;
Long saveId;
#Autowired
ProductRepository productRepository;
#Autowired
UserRepository userRepository;
CartRepository cartRepository;
#GetMapping("/shoppingCart")
#ResponseBody
public String showCart(Model model, Principal principal){
String nume = principal.getName();
cartRepository.save(saveId,userRepository.AiciVoiAveaId(nume));
Optional<Product> product = productRepository.findById(saveId);
model.addAttribute("product", product.get());
return "shoppingCart";
}
#PostMapping("/shoppingCart/{id}")
public String shoppingCart(#PathVariable Long id){
saveId = id;
return "redirect:/shoppingCart";
}
}
Error
2023-01-05T15:39:16.146+02:00 WARN 16652 --- [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cartRepository' defined in com.example.registrationlogindemo.repository.CartRepository defined in #EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Could not create query for public abstract java.util.List com.example.registrationlogindemo.repository.CartRepository.save(java.lang.Long,java.lang.Long); Reason: Failed to create query for method public abstract java.util.List com.example.registrationlogindemo.repository.CartRepository.save(java.lang.Long,java.lang.Long); No property 'save' found for type 'Cart'
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cartRepository' defined in com.example.registrationlogindemo.repository.CartRepository defined in #EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Could not create query for public abstract java.util.List com.example.registrationlogindemo.repository.CartRepository.save(java.lang.Long,java.lang.Long); Reason: Failed to create query for method public abstract java.util.List com.example.registrationlogindemo.repository.CartRepository.save(java.lang.Long,java.lang.Long); No property 'save' found for type 'Cart'
Can someone help me?
Hi, I have a problem too, I try to create a specific query for several actions and I get errors and I don't understand why...
Salut,
You can try with JpaRepository:
#Repository
public interface CartRepository extends JpaRepository<Cart, Long> {
#Query("FROM Cart WHERE user.id = :userID")
List<Cart> findAllByUserId(Long userID);
}
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "cart")
public class Cart {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_user", nullable = false)
private User user;
}
And then you can use the repository like so:
Cart cartToBeSaved = new Cart(userId);
cartRepository.save(cartToBeSaved); //cart id is auto-generated
Also, I would avoid declaring a global Long saveId;. It has no useful purpose and can lead to more serious issues when multiple users are accessing these endpoints.
I would also move some logic in a service class and I would encapsulate the repositories.
For example:
#Controller
#RequiredArgsConstructor
public class CartController {
private final CartService cartService;
#GetMapping("/shoppingCart")
public String showCart(Model model, Principal principal) {
Product product = cartService.saveProduct(...);
model.addAttribute("product", product.get());
return "shoppingCart";
}
#PostMapping("/shoppingCart/{id}")
public String shoppingCart(#PathVariable Long id){
//something here
}
}
#Service
#RequiredArgsConstructor
public class CartService {
private final ProductRepository productRepository;
private final UserRepository userRepository;
private final CartRepository cartRepository;
public Product saveProduct(...) {
//some business logic here
}
}
Your save() method contains a faulty sql command. The INSERT command for SQL does not work this way. I don't know exactly the qualities of your Cart object, but it needs to look like the following way.
#Modifying
#Query(name = "INSERT INTO cart (productId, userId) VALUES (:productID,:userID)",nativeQuery = true)
Cart save(#Param("productID") Long productId, #Param("userID") Long userID);
A SQL INSERT command must contain the column names of the corresponding table.
I also recommend using #Modifying annotation for commands such as INSERT, UPDATE, DELETE. You can find detailed information about #Modifying anatotion here.
I using get hibernate to get data. When i called data using specific parameter which return not query result, it shows bellow error
java.lang.NullPointerException
at com.rms.service.impl.ProductsServiceImpl.getAppProductItems(ProductsServiceImpl.java:143)
at com.rms.controller.RmsMobileAppController.getAppProductItems(RmsMobileAppController.java:59)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62).......
Here is my entity
#Entity
#Table(name = "RmsOptions")
public class RmsOptionsEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long id;
private String hardCode;
private String softCode;
private String codeDes;
private String status;
// getter setter
}
Here is my repository
public interface RmsOptionsRepo extends JpaRepository<RmsOptionsEntity, Long>{
#Query(" FROM RmsOptionsEntity WHERE hardCode = ?1 AND softCode =?2 AND status = 1")
RmsOptionsEntity getcodeDes(String hardCode,String softcord);
}
I called from ProductsServiceImpl class which is my service class . if parameter values matched it is working fine. When parameter values found no match it shows the error...
Here is my service
#Service
public class ProductsServiceImpl implements ProductsService {
#Autowired
private ProductCategoriesRepo productCategoriesRepo;
#Autowired
private RmsOptionsRepo rmsOptionsRepo;
#Override
public List<ProductAppItemsModel> getAppProductItems(String restaurantId, String restaurantBranchId) {
List<ProductAppItemsModel> list = new ArrayList<>();
List<ProductCategoriesInfo> productCatgoriesList = productCategoriesRepo.getProductCatgoriesList(restaurantId, restaurantBranchId);
try {
for (ProductCategoriesInfo categoriesInfo:productCatgoriesList){
List<ProductsInfo> products = productsRepo.getProducts(restaurantId, restaurantBranchId, categoriesInfo.getProductCategoryId());
}
}catch (Exception e){
e.printStackTrace();
}
return list;
}
}
How to handle null pointer exception. I just used now try...catch. Please suggest me..
if you use jpaRepo its a better way to create a method
public interface RmsOptionsRepo extends JpaRepository<RmsOptionsEntity, Long>{
#Query("SELECT * FROM RmsOptionsEntity WHERE hardCode = ?1 AND softCode =?2 AND status = 1")
RmsOptionsEntity findCodeDes(String hardCode,String softcord);
}
Shouldn't there be a SELECT in the start of the query?
public interface RmsOptionsRepo extends JpaRepository<RmsOptionsEntity, Long>{
#Query("SELECT * FROM RmsOptionsEntity WHERE hardCode = ?1 AND softCode =?2 AND status = 1")
RmsOptionsEntity getcodeDes(String hardCode,String softcord);
}
I am doing a project for my studies using Spring, Maven, Tomcat, mySQL. I would like to create a website where users can login and update their settings and based on these settings they generate stuff.
At the moment the login is working fine and new users can be registered and saved to the database. Now I created a new entity and made a one to one reletaionship between the two tables - one is the table of the login details like password and username and the other one contains the settings of this user. The issue I am facing:
I have some textfield and combobox in the UI with vaadin - I populate the fields and click save
A binder passes these settings to a service that saves the object
It gets the currently logged in user and loads it from the database
When SQL tries to save the objects it throws error:
Caused by: java.sql.SQLException: Field 'user_login_id' doesn't have a
default value
Here are the entities:
#Entity
#Table(name = "USERLOGIN")
public class UserLogin implements UserDetails {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#OneToOne(mappedBy = "userlogin")
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
**Other getters and setters**
}
#Entity
#Table(name = "USER")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
private Integer id;
#Column(name = "meal")
private Integer meal;
#OneToOne
#JoinColumn(name = "userlogin_id")
private UserLogin userlogin;
public UserLogin getUserLogin() {
return userlogin;
}
public void setUserLogin(UserLogin userLogin) {
this.userlogin = userLogin;
userLogin.setUser(this);
**Other getters and setters**
}
The service that saves the settings:
#Service
public class AddUserServiceImpl implements AddUserService{
#Autowired
private UserRepository userRepository;
#Autowired
private CurrentUserService currentUserService;
public void saveUser(User userDAO) {
User user = new User();
user.setMeal(userDAO.getMeal());
user.setUserLogin(currentUserService.getCurrentUser());
userRepository.save(user);
}
}
The repository extends the JPArepository:
#Repository
public interface UserRepository extends JpaRepository<User, Integer>{
}
And finally the service and the repository that loads the currently logged in user:
#Service
public class CurrentUserServiceImpl implements CurrentUserService {
#Autowired
UserLoginRepository userLoginRepository;
public String getCurrentUsername() {
return SecurityContextHolder.getContext().getAuthentication().getName();
}
public UserLogin getCurrentUser() {
return userLoginRepository.findByUserName(getCurrentUsername());
}
}
#Repository
public interface UserLoginRepository extends JpaRepository<UserLogin,
Integer> {
#Query("select u from UserLogin u where u.username=:username")
UserLogin findByUserName( #Param("username") String username);
}
Any help would be appreciated I am really new to this topic. So the main goal is that I want to have a table that stores properties for the currently logged in user - these settings should be able to be updated any time. Is there any best practice for this?
Thank you!
I have a little beginner's mistake in my project. I'm building a RESTful service with Spring Boot and my get method doesn't work.
I made an Entity called Project, that looks like this:
#Entity
#Table(name="project")
public class ProjectDto {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="id")
private long id;
#Column(name="caption")
private String caption;
..GETTERS AND SETTERS FOLLOW..
, than I created ProjectRepository like this:
#Repository
public interface ProjectRepository extends JpaRepository<ProjectDto, Long> {
public static final String GET_TIMELINE_PROJECT_CAPTIONS_QUERY = "SELECT
p.id, p.caption FROM ProjectDto p ORDER BY p.creationDate DESC";
#Query(GET_TIMELINE_PROJECT_CAPTIONS_QUERY)
public List<ProjectDto> getTimelineProjectCaptions();
}
..and a Controller
#RestController
#RequestMapping("/project")
public class ProjectController {
#Autowired
private ProjectRepository projectRepository;
#CrossOrigin(origins = "http://localhost:4200")
#RequestMapping(value = "/timeline", method = RequestMethod.GET)
public List<ProjectDto> getTimelineProjectCaptions() {
return projectRepository.getTimelineProjectCaptions();
}
}
but that gives[[5,"sddf"],[3,"asdf"],[2,"gb"],[1,"bg"]], which apparently isn't JSON
It is JSON. It's an array of arrays, which is what your query actually returns.
If you want an array of ProjectDto objects, the query should be
SELECT p FROM ProjectDto p ORDER BY p.creationDate DESC
Not sure why you're naming your entities with a Dto suffix. Entities are not DTOs. A DTO is a Data Transfer Object, i.e. an object specifically designed for data transfer.
You can use Projections.
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections.interfaces
If this is your Table
#Entity
#Table(name="project")
public class Project {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="id")
private long id;
#Column(name="caption")
private String caption;
#Temporal(TemporalType.DATE)
#Column(name="creationDate")
private Date creationDate;
// .. other columns ..
// ..GETTERS AND SETTERS FOLLOW..
Add an Interface-based projections
public interface ProjectCaption {
Long getId();
String getCaption();
}
Then add AS keyword on your query and change the return of your method
#Repository
public interface ProjectRepository extends JpaRepository<Project, Long>{
#Query("SELECT p.id AS id, p.caption AS caption FROM Project p ORDER BY p.creationDate DESC")
public List<ProjectCaption> getTimelineProjectCaptions();
}
You can try changing your method to something like this:
#RequestMapping(value = "/timeline", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<ProjectDto>> getTimelineProjectCaptions() {
return new ResponseEntity<List<ProjectDto>>(projectRepository.getTimelineProjectCaptions(), HttpStatus.OK);
}
I am using Spring Data Jpa and created a JpaRepository for my User class.
The repository works but Spring Tool Suite gives me a warning for one method.
Following are examples of my domain model classes and the repository:
User:
#Entity
public class User {
#Id
#GeneratedValue
private long id;
private String username;
#ManyToMany
#JoinTable( ... )
private Set<Role> roles = new HashSet<>();
// Getters & setters
}
Role:
#Entity
public class Role {
#Id
#GeneratedValue
private Long id;
private String name;
// Getters & setters
}
UserRepository:
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByRoles(Set<Role> roles);
}
STS marks the method findByRoles() and gives the following message: Parameter type (Set<Role>) does not match domain class property definition (Set).
Why do I get this warning?
change your method name like this
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findBy_Roles(Set<Role> roles);
}
for more details why its complaining see this page heading "2.4.3. Property expressions".
The signature of the method is wrong. It should be List<User> findByRolesIn(Set<Role> roles), because the argument is a collection.