JPA Entity class without "#Column" annotation - spring

I have this piece of code where the author creates a JPA Entity. Somehow, it's successfully working and that seems weird to me since not every field is annotated with "#Column". Based on that, here's my question:
How it is possible for this class to work properly (all data is being successfully recorded in the database) without every field not having a "Column" annotation (excepting "id")?
/**
* #author Ram Alapure
* #since 05-04-2017
*/
#Entity
#Table(name="User")
public class User {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "id", updatable = false, nullable = false)
private long id;
private String firstName;
private String lastName;
private LocalDate dob;
private String gender;
private String role;
private String email;
private String password;
#Override
public String toString() {
return "User [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", dob=" + dob + ", email="
+ email + "]";
}
}
For instance, here's another class which is working properly as well. But this time, with a "#Column" annotation in every field. I thought it was a pre-requisite to JPA create a column from the field.
#Entity
#Table(name = "address")
public class Address {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "address_id")
private long id;
#Column(name = "rua")
private String street;
#Column(name = "number")
private int number;
#Column(name = "complement")
private String complement;
#Column(name = "suburb")
private String suburb;
#Column(name = "city")
private String city;
#Column(name = "state")
private String state;
#Column(name = "country")
private String country;
#Column(name = "cep")
Getters and Setters were hidden from all pieces of code since they just look like regular getters and setters, not being necessary to be shown.

If you don't specify #Column annotation (Optional) then Hibernate uses default naming stretegy by using camel case.
firstName field becomes first_name column in Database.
You can also define your own naming stretegy according to your needs.
From the documentation.
strategy ; Hibernate 5 defines a Physical and Implicit naming strategies. Spring Boot configures SpringPhysicalNamingStrategy by default. This implementation provides the same table structure as Hibernate 4: all dots are replaced by underscores and camel cases are replaced by underscores as well.

this annotation means create table in database #Entity with all field in class same the name
the spring boot scan this annotation #Entity after scan
is inject and create Bean in IOC with fields
but if used #Column this help for mapping with Table field if change colume name in dataBase
and spring boot when scan component and see this annotation the bean is change with Colume name to name in database becouse we need success mapping with data base

Related

Spring Boot Entity how to check value if exist in another table by custom field

The user can search for products if any product shown in the result exists in the user_favorites table so the show flag tells the front-end this product was added for this user by user_id and product_id. with spring boot and spring data.
My Entity :
#Id
#Column(name = "catId")
private Integer catId;
#Column(name = "cat_no")
private String catNo;
#Column(name = "cat_sn")
private String catSn;
#Column(name = "doc_ref")
private String docRef;
#Column(name = "user_id")
private Integer userId;
#Column(name = "updated_at")
private String updatedAt;
#Column(name = "created_at")
private String createdAt;
I tried that using #Formula but nothing happing always returns null. and if it's done by #Formula how can i add parameters to #Formula
#Formula(value = "SELECT count(*) as checker FROM fb_user_favorites WHERE cat_id = 34699 AND user_id = '52') ")
#Transient
private String checker;
#Transient is part of JPA spec. In Hibernate fields marked with this annotation just simply ignored/excluded from any JPA engine/runtime logic.
#Formula is part of Hibernate. Fields, marked with it, don't persisted by Hibernate (first argument do not use #Transient as redundant), values are calculated by provided SQL when executing query for entity.
So for Hibernate to see this fields, they should not be excluded by #Transient
TL;DR remove #Transient annotation
Complicated but fast working way.
Adding isFavorite field to the entity:
#Transient
private boolean isFavorite;
Create an entity linking Product and User:
public class ProductFavorite {
#Id
#GeneratedValue(strategy = IDENTITY)
private Long id;
#ManyToOne(optional = false, fetch = LAZY)
private Product product;
#ManyToOne(optional = false, fetch = LAZY)
private User user;
}
Then create a repository with a method to find the user's favorite products:
#Repository
public interface ProductLikeRepository extends JpaRepository<ProductFavorite, Long> {
#Query("select f.product.id from ProductFavorite f where f.product in ?1 and f.user = ?2")
Set<Integer> findProductIdsByIdsAndUser(List<Product> products, User user);
}
And at the end, write a method that will fill in the isFavorite field:
public void fillFavorite(List<Product> products, User user) {
if (products.isEmpty()) {
return;
}
var likedIds = favoriteRepository.findProductIdsByIdsAndUser(products, user);
for (Product product : products) {
product.setFavorite(likedIds.contains(product.getId()));
}
}
You need to call it manually:
List<Product> products = productRepository.findAll();
fillFavorite(products, currentUser());

Spring JPA repository cannot resolve property of entity

Im trying to do a simple search for two columns for a table.
My customer entity class snipet:
#Entity
#Table(name = "CUSTOMER")
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "CUSTOMER_ID", nullable = false)
private int customer_id;
#Column(name = "FIRST_NAME", nullable = false)
private String first_name;
#Column(name = "LAST_NAME", nullable = false)
private String last_name;
#Column(name = "PHONE_NUMBER", nullable = false)
private String phone_number;
#Column(name = "EMAIL")
private String email;
my customerRepository class snipet:
#Repository
public interface CustomerRepository extends JpaRepository<Customer, Integer> {
List<Customer> findAllByFirst_nameAndLast_name(String firstName, String lastname);
}
When compiling and running springBoot i get this error:
nested exception is java.lang.IllegalArgumentException: Failed to create query for method public abstract java.util.List com.owl.owlserver.repositories.CustomerRepository.findAllByFirst_nameAndLast_name(java.lang.String,java.lang.String)! No property first found for type Customer!
So its not able to detect the fields in the customer object, should I be importing the customer class into the repository somehow?
The problem lies in your snake_case naming convention, it's recommended to use camelCase naming convention.
As the Spring docs say:
Because we treat the underscore character as a reserved character, we
strongly advise following standard Java naming conventions (that is,
not using underscores in property names but using camel case instead).
You can see a related JIRA issue here -- underscores are not supported in property names.
I would recommend keeping the properties in a camel-case as per standards
Because we treat the underscore character as a reserved character, we strongly advise following standard Java naming conventions (that is, not using underscores in property names but using camel case instead).
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "CUSTOMER_ID", nullable = false)
private int customerId;
#Column(name = "FIRST_NAME", nullable = false)
private String firstName;
#Column(name = "LAST_NAME", nullable = false)
private String lastName;
#Column(name = "PHONE_NUMBER", nullable = false)
private String phoneNumber;
#Column(name = "EMAIL")
private String email;
And then query as well as per Property Expressions
List<Customer> findAllByFirstNameAndLastName(String firstName, String lastname);
The whole point of Spring JPA is to simplify query building using the methods defined in Repository. The convention is to use the camelCase for naming field in Entity and the same while writing query methods. Just change the naming of entity fields from snake case to camel case and you're good to go.

join table and get data based on field value JPA

I have two entities
#Entity
public class Module {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
private String descr;
#OneToMany(cascade = {CascadeType.ALL})
#JoinColumn(name="ID", referencedColumnName="ID")
private List<Permissions> perms;
}
#Entity
public class Permissions {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private Integer clientId;
private String role;
private Character endorseCreate;
private Character endorseUpdate;
private Character endorseDelete;
private Character endorseView;
I am trying to fetch data by first Module.name and Permissions.clientId and Permissions.role
Something like in sql
select * from Module m, Permissions p where m.id=p.id and p.clientId=1 and p.role='ADMIN'
How can I achieve using JPA, I am using spring data aswell.
Can a method be declared in CRUD Repo provided by spring data?
I think the issue is I am unable to find way to pass values to fetch data.
Any help is greatly appreciated

How to make one Model for similar tables?

I have several similar tables in DB.
Now I use for each table own Model and Repository
But I think, this is not right decision.
Can I make a one Model and Repository for all similar tables?
#Entity
#Table(name = "BEDROOM", schema = "public")
public class BedroomModel extends AllFinishProductModel{
#Column(name = "PHOTO")
private String photo;
#Id
#Column(name = "ID")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#Column
private String name;
#Column(name = "DESCRIPTION")
private String description;
#Column(name = "STRUCTURE") //organza, curtain ....
private String structure;
#Column(name = "PAINT") //abstraction, geometric ....
private String paint;
#Column(name = "HEIGHT")
private String height;
#Column(name = "COLOR")
private String color;
#Column(name = "QUANTITY")
private Double quantity;
#Column(name = "PRICE")
private BigDecimal price;
#Column(name = "SEWED")
private String itIsSewed;
... getters and setters
}
I have a similar tables: CABINET, GUESTROOM, CHILDREN_ROOM, KITCHEN, CURTAIN and TULLE.
Which code should be used for repository?
I tried to find answers to the questions inhttps://docs.spring.io/spring-data/data-commons/docs/1.6.1.RELEASE/reference/html/repositories.html
But I don't find answers here.
Can you give advice, how to make it or link?
You can use entity inheritance with #MappedSuperclass annotation on parent class to get common properties in child classes/tables.
So, for example you have a parent Room entity with common properties, which you annotate with #MappedSuperclass.
#MappedSuperclass
public class Room {
#Column
private String name;
#Column(name = "DESCRIPTION")
private String description;
// some more common properties
}
And concrete rooms, e.g.:
#Entity
public class Bedroom extends Room
{
// common properties will be inherited
private Bed bed;
private NightLamp nightLamp;
}
Now, the important part is that Room is not mapped as any table. The room is a "virtual" table, which doesn't exist in the db. Only concrete entities exist as tables, like Bedroom.
Here you have the link to the official javadoc:
http://docs.oracle.com/javaee/5/api/javax/persistence/MappedSuperclass.html

Spring + hibernate one to one mapping

I am developing web application using spring and hibernate. I am using one to one mapping between two tables employee and PersonelDetails.
below are my bean classes
=======================Employee=====================================
#Entity
#Table(name="employee")
public class Employee {
#Id
#Column
#GeneratedValue
private int empid;
#Column
private String firstName;
#Column
private String lastName;
#Column
private String email;
#Column
private String password;
#Column
private boolean isAdmin;
#Column
private boolean isActive;
#Column
private boolean isLocked;
//getter setters
====================PersonalDetails class====================
#Entity
#Table(name="PersonalDetails")
public class PersonalDetails {
#Column
#Id
private int empid;
#Column
private String personalEmail;
#Column
private String mob;
#Column
private String permenantAdress;
#Column
private String currentAddress;
#Column
private String gender;
#Column
private String maritialStatus;
#MapsId
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "empid", referencedColumnName = "empid")
#ForeignKey(name="empid")
private Employee employee;
//getter setters
In my application table employee is filled by Admin user while creating new employee after that employyee himself fill personalDetails table by login to his accountCreated by Admin)
Now when I try to send personal details bean to hibernate layer first I have to get the employee bean from employee table then call setEmployee method over personalDetails class and save employee bean in personalDetails and send to hibernate layer for saving in database.
So while getting employee bean from database and again send back through personalDetails bean leads to a performance issue.
Can anyone help here to clarify while saving data in child table(PersonalDetails) is it really mandatory to pass parent object(Employee) ?
=======================code to store personalDetails===============
#RequestMapping(value="addpersonal")
public ModelAndView addPersonalDetails(#ModelAttribute("personalDetails") PersonalDetails personalDetails) {
//personalDetails.setEmpid(1);
personalDetails.setCurrentAddress("niljyoti");
personalDetails.setMob("9405715872");
personalDetails.setPermenantAdress("address");
Employee e = empService.getEmployeebyUserName(uname);
personalDetails.setEmployee(e);
personalDetailsService.addPersonalDetails(personalDetails);
return new ModelAndView("home");
}
On read:
You can change fetch strategy if you are worried.
Based od JPA spec, default fetch type for #OneToOne is EAGER.
By setting fetch = FetchType.LAZY, instead of real PersonalDetails object, an object of a subclass behaving as a proxy is returned. Hence, selecting from employee table starts only after getEmployee is called.
On write:
You need to specify connection between entities, in your model, the only way is the employee field. However, you can specify mappedBy, see answer to this question:
Java: Hibernate #OneToOne mapping

Resources