I'm trying to learn spring boot with JPA. How to create an entity that only has selected columns of a table? I can do this using jdbcTemplate but is it also possible using JPA?
I tried using the SELECT NEW but it gives me a null pointer exception error on the em.createQuery execution. Does it mean I get no results? Can you help me pinpoint my error?
Here is my code :
EntityManager em;
String queryStr =
"SELECT NEW com.lms.app.user.User(c.id.username, c.password, c.emailadd) FROM TBUSER AS c";
TypedQuery<User> query =
em.createQuery(queryStr, User.class);
List<User> results = query.getResultList();
User.class
public class User {
private String name;
private String password;
private String email;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
TBUSER columns looks like this :
username varchar (primary key)
password
emailadd
then more columns here..
Related
i'm new to Springboot. I'm trying to implement a simple REST api using :
-Springboot, JPA & rest along with hibernate
I have a 2 tables database, Notebook that contains 1 to many notes
I already setup the 2 tables and relationships. I also created a NotebookRepository and NoteRepository to get basic CRUD operations via the springboot rest. The Database connection and relationships are functionning
but i don't know how to add a new note (it has a notebook_id foreign key which msut NOT be NULL) and everytime i tryto post something along these lines
{
"title:"abc",
"text":"whatever",
"notebook":{
"id":2
}
}
i get this error :
Caused by: java.sql.SQLIntegrityConstraintViolationException: Column 'notebook_id' cannot be null
#Entity
#Table(name="notebook")
public class NoteBook {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id")
private int id;
#Column(name="name")
private String name;
#OneToMany(mappedBy="notebook", cascade=CascadeType.ALL)
List<Note> notes;
public NoteBook() {
}
public NoteBook(String name) {
this.name = name;
}
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 List<Note> getNotes() {
return notes;
}
public void setNotes(List<Note> notes) {
this.notes = notes;
}
public void addNote(Note note) {
if(notes == null) {
notes = new ArrayList<>();
}
note.setNotebook(this);
notes.add(note);
}
#Entity
#Table(name="note")
public class Note {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id")
private int id;
#Column(name="title")
private String title;
#Column(name="text")
private String text;
#ManyToOne(cascade={CascadeType.MERGE, CascadeType.DETACH, CascadeType.PERSIST, CascadeType.REFRESH})
#JoinColumn(name="notebook_id")
private NoteBook notebook;
public Note() {
}
public Note(String title, String text) {
this.title = title;
this.text = text;
}
#RepositoryRestResource(collectionResourceRel = "note", path = "notes")
public interface NoteRepository extends JpaRepository<Note, Integer>{
//No code...
}
#RepositoryRestResource(collectionResourceRel = "notebook", path = "notebooks")
public interface NotebookRepository extends JpaRepository<NoteBook, Integer>{
}
The problem is that the class Note doesn't have a constructor with NoteBook parameter to pass the created NoteBook object to, so the solution is to add this constructor:
public Note(String title, String text, NoteBook noteBook) {
this.title = title;
this.text = text;
this.noteBook = noteBook;
}
and it's enough to send the JSON object as you do, but just be aware of case-sensitivity:
{ "title:"abc", "text":"whatever", "noteBook":{ "id":2 } }
I think you need to add referencedColumnName = "id" for JoinColumn annotation for notebook field in Note class.
Maybe you have problem with IDENTITY generation type. See this problem with null pointer
I have a User Entity and an Order Entity.
One of the field in order entity is date.
Till now i have the user enter the date.
Now i want that at the time post request is made the date is automatically set to the current date and stored in the database.
Tried using #Prepersist annotation But since this is my first API that i am developing using springBoot , I don't really know how to use it.
User Entity
#Entity
public class User {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private BigInteger id;
#NotEmpty(message = "Name is compulsory")
#Pattern(regexp="^[A-Za-z]*[A-Za-z-'. ]*[A-Za-z]*$",message = "Name has invalid characters")
private String username;
//#NotEmpty(message = "Phone Number is compulsary")
#Range(min = 6400000000L ,max=9999999999L)
private Long phoneNumber;
#NotEmpty(message = "Address is compulsary")
private String address;
public User(){}
public User(BigInteger id, String username, Long phoneNumber, String address) {
super();
this.id = id;
this.username = username;
this.phoneNumber = phoneNumber;
this.address = address;
}
public BigInteger getId() {
return id;
}
public void setId(BigInteger id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Long getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(Long phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
Order Entity
#Entity
public class Orders {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private BigInteger id;
#CreationTimestamp
#Temporal(TemporalType.TIMESTAMP)
private Date date;
#ManyToOne
private User user;
public Orders(){}
public Orders(BigInteger id, Date date,BigInteger userId) {
super();
this.id = id;
this.date = date;
this.user=new User(userId," ",0000000000L," ");
}
public BigInteger getId() {
return id;
}
public void setId(BigInteger id) {
this.id = id;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
Order Controller
#RestController
public class OrdersController {
#Autowired
private OrdersService ordersService;
#ApiOperation(value="Show all orders")
#RequestMapping("/orders")
public Iterable<Orders> getAllOrders()
{
return ordersService.getAllOrders();
}
#ApiOperation(value="Show a particular Order")
#RequestMapping("/orders/{orderId}")
public Orders getOrderById(#PathVariable BigInteger orderId)
{
return ordersService.getOrderById(orderId);
}
#ApiOperation(value="Show all orders of a particular User")
#RequestMapping("/users/{id}/orders")
public List<Orders> getOrders(#PathVariable BigInteger id) {
return ordersService.getOrders(id);
}
#ApiOperation(value="Show an order for a User")
#RequestMapping("/users/{userId}/orders/{id}")
public Orders getOrder(#PathVariable BigInteger id){
return ordersService.getOrder(id);
}
#ApiOperation(value="Adds a new Order")
#RequestMapping(method = RequestMethod.POST,value = "/users/{userId}/orders")
public Orders addOrder(#PathVariable BigInteger userId,#RequestBody Orders orders) {
orders.setUser(new User(userId," ",0000000000L," "));
return ordersService.addOrder(orders);
}
#ApiOperation(value="Alter an Order")
#RequestMapping(method = RequestMethod.PUT, value="/users/{userId}/orders/{id}")
public Orders updateOrder(#RequestBody Orders order,#PathVariable BigInteger id,#PathVariable BigInteger userId)throws Exception {
order.setUser(new User(userId," ",0000000000L," "));
return ordersService.updateOrder(order, id);
}
#ApiOperation(value="Delete an Order")
#RequestMapping(method = RequestMethod.DELETE, value="/orders/{id}")
public void deleteOrder(#PathVariable BigInteger id){
ordersService.deleteOrder(id);
}
}
#PrePersist is a JPA annotation and therefore should work in all compatible persistence frameworks. It indicates a method that should be invoked on particular entity lifecycle event. (Other events are well documented in the Hibernate user guide here).
Add this to your entity:
#Temporal(TemporalType.TIMESTAMP)
#Column(nullable = false)
private Date timestamp;
#PrePersist
private void onCreate() {
timestamp = new Date();
}
As for assigning/creating the entity in the controller, it is a good practice to use DTO (data transfer objects) in your controller (#RequestBody OrderDto orderDto) and then use some method to populate a new entity instance with those values. Most common options are
modelmapper
manually
...
Order o = new Order();
o.user = userDao.findById(orderDto.getUserId());
...
// persist o
This question already has answers here:
Cannot create a database table named 'user' in PostgreSQL
(5 answers)
Unable to use table named "user" in postgresql hibernate
(6 answers)
Closed 3 years ago.
i am trying to setup spring boot project by using postgres database. my entities are : -
USER
#Entity
public class User implements UserDetails {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id", nullable = false, updatable = false)
private Long id;
private String username;
private String password;
private String firstName;
private String lastName;
#Column(name="email", nullable = false, updatable = false)
private String email;
private String phone;
private boolean enabled=true;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JsonIgnore
private Set<UserRole> userRoles = new HashSet<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
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;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public Set<UserRole> getUserRoles() {
return userRoles;
}
public void setUserRoles(Set<UserRole> userRoles) {
this.userRoles = userRoles;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Set<GrantedAuthority> authorites = new HashSet<>();
userRoles.forEach(ur -> authorites.add(new Authority(ur.getRole().getName())));
return authorites;
}
#Override
public boolean isAccountNonExpired() {
// TODO Auto-generated method stub
return true;
}
#Override
public boolean isAccountNonLocked() {
// TODO Auto-generated method stub
return true;
}
#Override
public boolean isCredentialsNonExpired() {
// TODO Auto-generated method stub
return true;
}
#Override
public boolean isEnabled() {
return enabled;
}
}
ROLE
#Entity
public class Role {
#Id
private int roleId;
private String name;
#OneToMany(mappedBy = "role", cascade=CascadeType.ALL, fetch=FetchType.LAZY)
private Set<UserRole> userRoles = new HashSet<>();
public int getRoleId() {
return roleId;
}
public void setRoleId(int roleId) {
this.roleId = roleId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<UserRole> getUserRoles() {
return userRoles;
}
public void setUserRoles(Set<UserRole> userRoles) {
this.userRoles = userRoles;
}
}
USER_ROLE
#Entity
#Table(name="user_role")
public class UserRole {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long userRoleId;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name="user_id")
private User user;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name="role_id")
private Role role;
public UserRole(){}
public UserRole(User user, Role role) {
this.user = user;
this.role = role;
}
public Long getUserRoleId() {
return userRoleId;
}
public void setUserRoleId(Long userRoleId) {
this.userRoleId = userRoleId;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
}
and my application.properties file looks like:-
server.port=5060
spring.thymeleaf.cache=false
spring.datasource.url=jdbc:postgresql://localhost:5432/pcms
spring.datasource.data-username=sagar
spring.datasource.password=sagar
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQL94Dialect
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults = false
so whenever i run this application. user_role and role tables are created successfully on postgresql database. but user entity throws an exception.
the error says:-
2018-05-07 15:44:15.847 WARN 23619 --- [ restartedMain] o.h.t.s.i.ExceptionHandlerLoggedImpl : GenerationTarget encountered exception accepting command : Error executing DDL via JDBC Statement
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL via JDBC Statement
at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:67) ~[hibernate-core-5.2.16.Final.jar:5.2.16.Final]
at org.hibernate.tool.schema.internal.SchemaCreatorImpl.applySqlString(SchemaCreatorImpl.java:440) [hibernate-core-5.2.16.Final.jar:5.2.16.Final]
at org.hibernate.tool.schema.internal.SchemaCreatorImpl.applySqlStrings(SchemaCreatorImpl.java:424) [hibernate-core-5.2.16.Final.jar:5.2.16.Final]
at org.hibernate.tool.schema.internal.SchemaCreatorImpl.createFromMetadata(SchemaCreatorImpl.java:375) [hibernate-core-5.2.16.Final.jar:5.2.16.Final]
at org.hibernate.tool.schema.internal.SchemaCreatorImpl.performCreation(SchemaCreatorImpl.java:166) [hibernate-core-5.2.16.Final.jar:5.2.16.Final]
at org.hibernate.tool.schema.internal.SchemaCreatorImpl.doCreation(SchemaCreatorImpl.java:135) [hibernate-core-5.2.16.Final.jar:5.2.16.Final]
at org.hibernate.tool.schema.internal.SchemaCreatorImpl.doCreation(SchemaCreatorImpl.java:121) [hibernate-core-5.2.16.Final.jar:5.2.16.Final]
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:155) [hibernate-core-5.2.16.Final.jar:5.2.16.Final]
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:72) [hibernate-core-5.2.16.Final.jar:5.2.16.Final]
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:312) [hibernate-core-5.2.16.Final.jar:5.2.16.Final]
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:460) [hibernate-core-5.2.16.Final.jar:5.2.16.Final]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:892) [hibernate-core-5.2.16.Final.jar:5.2.16.Final]
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) ~[spring-boot-devtools-2.0.1.RELEASE.jar:2.0.1.RELEASE]
Caused by: org.postgresql.util.PSQLException: ERROR: syntax error at or near "user"
Position: 108
as you can see the error points on USER entity. but the same entity runs fine when the application is connected to mysql database. i could not quite figure out what is the real error behind it.
User is actually a reserved keyword that Spring JPA doesn't "escape" as-is. However, you can do the keyword escape like so in your entity declaration:
#Entity
#Table(name = "\"User\"")
public class User implements UserDetails { ... }
Spring is likely escaping it for you in your MySql database or taking care of it for you in some other way; not the case for your PostgreSQL DB.
Not sure why I have an issue here, but when I save with a CrudRepository with these objects, I get the SerializationException (with no further information). Can someone take a look at my objects and offer me some insight into why they can't serialize? My pom.xml is attached last as well in case that helps somehow. I'm using a Postgres database.
EDIT: The database and now - tables are created, but objects are not creating rows.
The actual CrudRepository interface:
public interface AccountRepository extends CrudRepository<ZanyDishAccount, String> {}
ZanyDishAccount entity:
#Entity
public class ZanyDishAccount {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id; // internal id of the customer account for a Zany Dish subscription
private String status;
#OneToOne(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "company_id")
private Company company;
#OneToOne(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "order_id")
private Order order;
public ZanyDishAccount() {}
public ZanyDishAccount(Company company, Order order) {
this.company = company;
this.order = order;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
#Override
public String toString()
{
return "ClassPojo [id = "+id+ ", company = " + company + ", status = " + status + "]";
}
}
Company entity:
#Entity
public class Company {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
Long id;
private String phoneNumber;
private String website;
private String name;
private String uuid;
private String country;
public Company() {}
public Company(String phoneNumber, String website, String name, String uuid, String country) {
this.phoneNumber = phoneNumber;
this.website = website;
this.uuid = uuid;
this.country = country;
}
public String getPhoneNumber ()
{
return phoneNumber;
}
public void setPhoneNumber (String phoneNumber)
{
this.phoneNumber = phoneNumber;
}
public String getWebsite ()
{
return website;
}
public void setWebsite (String website)
{
this.website = website;
}
public String getName ()
{
return name;
}
public void setName (String name)
{
this.name = name;
}
public String getUuid ()
{
return uuid;
}
public void setUuid (String uuid)
{
this.uuid = uuid;
}
public String getCountry ()
{
return country;
}
public void setCountry (String country)
{
this.country = country;
}
#Override
public String toString()
{
return "ClassPojo [phoneNumber = "+phoneNumber+", website = "+website+", name = "+name+", uuid = "+uuid+", country = "+country+"]";
}
}
Order entity:
#Entity
#Table(name = "_order")
public class Order {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
Long id;
private String pricingDuration;
private Items[] items;
private String editionCode;
public Order() {}
public Order(String pricingDuration, Items[] items, String editionCode) {
this.pricingDuration = pricingDuration;
this.items = items;
this.editionCode = editionCode;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getPricingDuration ()
{
return pricingDuration;
}
public void setPricingDuration (String pricingDuration)
{
this.pricingDuration = pricingDuration;
}
public Items[] getItems ()
{
return items;
}
public void setItems (Items[] items)
{
this.items = items;
}
public String getEditionCode ()
{
return editionCode;
}
public void setEditionCode (String editionCode)
{
this.editionCode = editionCode;
}
#Override
public String toString()
{
return "ClassPojo [pricingDuration = "+pricingDuration+", items = "+items+", editionCode = "+editionCode+"]";
}
}
Thanks for your help!
Mike
Hm, this seems multi-faceted. Let's see if I can help at all. Last thing first...
No tables being created automatically.
I would take a look at this section in Spring's docs for the most basic approach: Initialize a database using Hibernate. For example, spring.jpa.hibernate.ddl-auto: create-drop will drop and re-create tables each time the application runs. Simple and easy for initial dev work. More robust would be leveraging something like Flyway or Liquibase.
Serialization issue
So without logs, and the fact that you have no tables created, the lack of a persistence layer would be the assumed culprit. That said, when you have tables and data, if you do not have a repository for all of the related tables, you'll end up with a StackOverflow error (the serialization becomes circular). For that, you can use #JsonBackReference (child) and #JsonManagedReference (parent). I have been successful using only #JsonBackReference for the child.
Items[]
I'm not sure what Item.class looks like, but that looks like an offensive configuration that I missed the first round.
Change private Items[] items; to private List<Item> items = new ArrayList<Item>();. Annotate with #ElementCollection.
Annotate Item.class with #Embeddable.
I have one User class like this:
#Document(collection = "users")
public class User {
#Id
private String id;
String username;
String password;
String description;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
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;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#Override
public String toString() {
return "User[id=" + id + ", username=" + username + ", password=" + password + ", description"
+ description + "]";
}
}
I am able to perform limited update. Like:
Query searchQuery = new Query(Criteria.where("id").is("shashi"));
mongoDBClient.updateFirst(searchQuery, Update.update("password", "newpassword"), User.class);
Now if I want to update rest other fields(username and description) of User class, I need to call updateFirst method so many times.
I want to avoid this and pass the entire object to updateFirst method. Something like:
mongoDBClient.updateFirst(searchQuery, Update.update(userObject), User.class);
Basically, I want to edit all/multiple fields in one call using java POJO object. How I can achieve this?
Edit/All multiple fields in one call using java POJO object, can be done as shown below
1) Query the document which need to be updated --> we get the java object
2) Do all modifications in the java object
3) Save the object
Code:
Query query = new Query();
query.addCriteria(Criteria.where("id").is("shashi"));
User user = mongoOperation.findOne(query, User.class);
//modify the user object with the properties need to be updated
//Modify password and other fields
user.setPassword("newpassword");
user.setDescription("new description");
user.setUsername("NewUserName");
//save the modified object
mongoOperation.save(user);