JPA: Why is ID of selected object null? - java

In my JPA application, I am using the following SELECT statement to retrieve a user from the database:
TypedQuery<AppAdmin> query = entityManager.createQuery("SELECT a FROM AppAdmin a WHERE a.username=:username", AppAdmin.class);
query.setParameter("username", username);
AppAdmin user = query.getSingleResult();
However, the user's id field is always null, even though I checked that the field is not null in the database. What could be the cause of this behaviour?
The following shows my AppAdmin class:
#Entity
#Table(name = "u_userdetails_admin")
public class AppAdmin extends BasicUser {
/**
*
*/
private static final long serialVersionUID = -41356272870596876L;
#Id
#GeneratedValue(generator = "uuid2")
#GenericGenerator(name = "uuid2", strategy = "uuid2")
#Column(name = "id", columnDefinition = "BINARY(16)")
private UUID id;
protected AppAdmin(){}
public AppAdmin(
#JsonProperty("id") UUID id,
#JsonProperty("username") String username,
#JsonProperty("password") String password,
#JsonProperty("registrationDate") LocalDate registrationDate,
#JsonProperty("locked") boolean locked,
#JsonProperty("enabled") boolean enabled,
#JsonProperty("activationKey") String activationKey,
#JsonProperty("email") String email) {
super(id, username, password, registrationDate, locked, enabled, activationKey, email, new ArrayList<String>());
}
}

This solves the problem: AppAdmin extends BasicUser and I defined an id field in both classes. The inheritance strategy is set to InheritanceType.JOINED, and removing the id defintion in AppAdmin causes the IDs to be loaded again. However, I am not sure if this is the real cause of the problem, as it used to work before until it just stopped working at some point.

Related

Spring Boot Data JPA - query using an interface projection returns all fields if there are collections in the projection

There are several entities in the project, such as User and enum Role, which is used in the User entity as #ElementCollection.
User entity
public class User {
#Id
#GeneratedValue(strategy = IDENTITY)
private Long id;
#Column(unique = true, nullable = false)
private String username;
#Column(unique = true, nullable = false)
private String email;
#Column(nullable = false, length = 80)
private String password;
#Column(nullable = false)
private Boolean isActive = false;
#ElementCollection(fetch = LAZY)
private Set<Role> roles = new HashSet<>(Set.of(USER));
}
Role enum
public enum Role implements GrantedAuthority {
USER, ADMIN;
#Override
public String getAuthority() {
return name();
}
}
For the User entity, I created a special projection that includes the following fields, including the role collection:
public interface UserProjection {
String getUsername();
String getPassword();
Set<Role> getRoles();
}
And a JPA repository with a method that finds by username the user using this projection:
#Repository
public interface UserRepository extends JpaRepository<User, Long> {
#EntityGraph(attributePaths = {"roles"})
Optional<UserProjection> findUserByUsername(String username);
}
When I call this method, I run into the problem that the query contains all fields, including those not specified in the projection:
select
user0_.id as id1_1_,
user0_.email as email2_1_,
user0_.is_active as is_activ3_1_,
user0_.password as password4_1_,
user0_.username as username5_1_,
roles1_.users_id as users_id1_2_0__,
roles1_.roles as roles2_2_0__
from
users user0_
left outer join
users_roles roles1_
on user0_.id=roles1_.users_id
where
user0_.username=?
But if I remove the collection from the projection, the query starts working correctly:
select
user0_.username as col_0_0_,
user0_.password as col_1_0_
from
users user0_
where
user0_.username=?
Can you tell me how to fix this error? I couldn't find any clues, including in the Spring Data JPA documentation, which gave examples of the most basic use cases of projections. Thanks

How to map java enum to postgreSQL enum for conditional select query

I am using PostgreSQL and java for building the backend of an application.
In PostgreSQL, I have used an enum here.
and in java I have used enum for layer variable also.
#Entity
#Getter
#Setter
#Table(name = "usecase_details")
#JsonIgnoreProperties
public class UsecaseDetails {
#Id
#Column(name="id", nullable = false)
#SequenceGenerator(name= "usecase_details_sequence", sequenceName
="usecase_details_id_sequence")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator =
"usecase_details_sequence" )
private Long id;
#Column(columnDefinition = "layer_t", nullable = false)
#Enumerated(EnumType.STRING)
#Type(type = "com.apple.exampleportal.portal.utility.EnumTypePostgreSql")
private Layer layer;
private Long check_id;
private int usecase_id;
private String description;
private String fix_type;
private String radars;
private boolean show_usecase = true;
public UsecaseDetails(Long id, Layer layer, Long check_id, int usecase_id, String description, String fix_type, String radars, boolean show_usecase) {
this.id = id;
this.layer = layer;
this.check_id = check_id;
this.usecase_id = usecase_id;
this.description = description;
this.fix_type = fix_type;
this.radars = radars;
this.show_usecase = show_usecase;
}
// skipping getter setter for brevity
EnumTypePostgreSql. class is
public class EnumTypePostgreSql extends EnumType {
#Override
public void nullSafeSet(
PreparedStatement st,
Object value,
int index,
SharedSessionContractImplementor session)
throws HibernateException, SQLException {
st.setObject(
index,
value != null ?
((Enum) value).name() :
null,
Types.OTHER
);
}
}
and my custom queries are as follows:
public interface UsecaseRepository extends JpaRepository<UsecaseDetails, Long> {
#Query(value = "SELECT description, fix_type, usecase_id, layer FROM public.usecase_details WHERE layer = :layer", nativeQuery = true)
List<UsecaseDetails> findUsecaseByLayer(Layer layer);
#Query(value = "INSERT INTO public.usecase_details(description,fix_type, usecase_id, layer)\n"+
"\tVALUES (?,?,?,?)", nativeQuery = true)
UsecaseDetails insertDetails(UsecaseDetails usecaseDetails);
The insert query is working properly but for findUsecaseByLayer , I am getting the following error.
I am unable to detect my mistake. Please help!
There's probably something wrong with how you declare the type in EnumTypePostgreSql.
I also noticed this in your custom query: WHERE layer: = ?layer is the : wanted before your equal?
The solution I use:
Remove the #Type annotation from your entity column
#Column(columnDefinition = "layer_t", nullable = false)
#Enumerated(EnumType.STRING)
private Layer layer;
Then add to your JDBC URI:
?stringtype=unspecified
This will automatically cast the string to its enum type.

How can we save the form data from jsp file in database using spring boot?

I am creating a spring boot API which basically asks the user to create an account.
The account details are showed on a form.
I want to fetch the details from the form and save that to the database(MYSQL).
The model class is as follows:
#Table(name = "user")
public class User {
#Id
#Column(name = "ID")
private int ID;
#Column(name = "Fname")
private String fName;
#Column(name = "Lname")
private String lName;
#Column(name = "dob")
private String dob;
#Column(name = "email")
private String email;
#Column(name = "pWord")
private String pWord;
}
The controller class is as follows:
public class MController {
#Autowired
private UserRepository userRepository;
#PostMapping("/successSignUp")
public String dataToDB(#ModelAttribute("User") User formData, Model model) {
userRepository.save(new User(formData.getFname(), formData.getLname(), formData.getDob(), formData.getEmail(), formData.getPassword()));
model.addAttribute("user", new User());
return "welcomeUser";
}
When i am executing this code, i am getting the following error:
java.sql.SQLSyntaxErrorException: Unknown column 'p_word' in 'field list'
What am I doing wrong here?
Thanks in advance.
Spring framework changes the camel case to snake case internally.
This is part of Spring Boot Naming Strategies:
We can override these values, but by default, these will:
Change camel case to snake case
Replace dots with underscores
Lower-case table names
Can you try to update column name as pword instead of pWord ?
#Column(name = "pword")
private String pWord;
it will be considered as p_word if you use 'pWord'. please update column name as 'pword' and try.
example:
#Entity
public class Account {
#Id
private Long id;
private String defaultEmail;
}
And then turn on some SQL debugging in our properties file:
hibernate.show_sql: true
At startup, we'll see the following create statement in our logs:
Hibernate: create table account (id bigint not null, default_email varchar(255))
The easiest solution to fix this is to put the column names in lowercase or uppercase.
#Column(name = "pword")
private String pWord;
or
#Column(name = "PWORD")
private String pWord;
This will avoid that spring convert the name into snakecase.
Name of the columns in MySql are not case sensitive, so it will work.

How edit a pojo in spring java?

I want to edit a user, should I replace it with another user? Or should I just replace the attributes?
I have this controller
#PostMapping("/edit")
public ResponseEntity<User> editUser(#RequestBody User user) {
log.info("EDIT");
return new ResponseEntity<User>(userServiceImpl.editUser(user), HttpStatus.OK);
}
this my service:
public User editUser(User user) {
User owner = userRepository.findById(user.getId());
owner=user;
userRepository.save(user);
return owner;
}
the class User is
#Entity
#Table(name = "User")
public class User implements Serializable {
private static final long serialVersionUID = -3009157732242241606L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "name")
private String name;
#Column(name = "password")
private String password;
#Column(name = "email")
private String email;
I need to do something like that, I mean do an insert query to the bd?
#Modifying
#Query("update User u set u.firstname = ?1, u.lastname = ?2 where u.id = ?3")
void setUserInfoById(String firstname, String lastname, Integer userId);
To make it clear.
Let think this simple.
You have userRepository.save(user);
What will it do?
If this object don't have an Id ~> Save it as new object
If this user HAD an ID, it will check OVERWRITE if the id is EXIT
So if you wanna Edit just SOME FIELDS, let do like convention
domain:port/user/{userId}/ (PUSH) and give some field need to change here.
~> Get the real obj in DB ~> update the object and do with SAVE.
/ ~> Or you can do the query update directly if you want
Just save updated user
public User editUser(User user) {
return userRepository.save(user);
}
It will be enough.
Here, this will ensure that no data is lost and a new record is not generated.
public User editUser(User user) {
User owner = userRepository.findById(user.getId());
if(user.getName != null){
owner.setName(user.getName);
}
if(user.getPassword != null){
owner.setPassword(user.getPassword);
}
if(user.getEmail != null){
owner.setEmail(user.getEmail);
}
return userRepository.save(owner);
}

hibernate filter not working in the case of session.get() but working in the case of session.createQuery()

I am using hibernate 4. I am writing a filter. The strange thing I noticed is the filter is not getting applied if I use session.get() method
public SecurityAgency getSecurityAgencyById(int id) {
Session session = this.sessionFactory.getCurrentSession();
session.enableFilter("byEnabled");
SecurityAgency s = (SecurityAgency)session.get(SecurityAgency.class, new Integer(id));
return s;
}
Filter starts working as soon as I replace the session.get method with session.createQuery method and send a HQL query. I am unable to find any reason for this behaviour in the hibernate documentation.
FIlter declaration in securtiy agency class
#Entity
#Table(name="security_agency")
public class SecurityAgency implements java.io.Serializable {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name="name")
private String name;
#Column(name="code")
private String code;
#Column(name="website")
private String website;
#Column(name="tan")
private String tan;
#Column(name="email")
private String email;
#Column(name="pan")
private String pan;
#Column(name="created_at")
private Date createdAt;
#Column(name="created_by")
private long createdBy;
#Column(name="modified_at")
private Date modifiedAt;
#Column(name="modified_by")
private long modifiedBy;
#OneToMany(mappedBy="securityAgency",fetch = FetchType.EAGER)
#JsonIgnoreProperties("securityAgency")
#Filter(name = "byEnabled", condition = "is_enabled= 1")
private Set<ContactPerson> contactPersons = new HashSet<ContactPerson>(0);
public SecurityAgency() {
}
Contact person class
#Entity
#Table(name = "contact_person")
#FilterDefs({
#FilterDef(name="byEnabled"),
#FilterDef(name="bySecurityAgency",parameters = #ParamDef(name="agency_id", type="int"))
})
#Filters({
#Filter(name="byEnabled", condition = "is_enabled = 1"),
#Filter(name="bySecurityAgency", condition = "agency_id= :agency_id ")
})
public class ContactPerson implements java.io.Serializable {
Filter doesn't work if you are fetching using id value.Use Query interface instead. See this thread
if you want to use table column values you need to use filter join table ( #FilterJoinTable ), #Filter is applied to target entity rather than table
try,
#FilterJoinTable(name = "byEnabled", condition = "is_enabled= :enabled")
private Set<ContactPerson> contactPersons = new HashSet<ContactPerson>(0);
get
session.enableFilter("byEnabled").setParameter("enabled", Integer.valueOf(1));

Categories