Java EE, Integer to User? - java

I have recently asked quite similar question here, but answer does not solve my new problem.
I have two tables: User and Book, they are in ManyToOne relation. The Book table has attribute called user_id that connects both tables. Using Eclipse I generated entity classes, and "user_id" was created not as Integer like in database, but:
#JoinColumn(name="user_id")
private User user;
So now when i try to create new "Book" like this:
public String saveData() {
if(!validate()){
...
if (book != null) {
System.out.println(getUser());
setName(book.getName());
System.out.println("Post3");
setSurname(book.getSurname());
setAdress(book.getAdress());
setSize(book.getSize());
setContact(book.getContact());
setPrice(book.getPrice());
setOthers(book.getOthers());
setIsReady(book.getIsReady());
setRooms(book.getRooms());
setUser(book.getUser());
System.out.println(user);
}
private boolean validate() {
FacesContext ctx = FacesContext.getCurrentInstance();
boolean result = false;
System.out.println("validate");
if (ctx.getMessageList().isEmpty()) {
book.setName(name.trim());
book.setSurname(surname.trim());
book.setAdress(adress.trim());
book.setSize(size.trim());
book.setContact(contact.trim());
book.setPrice(price);
book.setOthers(others.trim());
book.setIsReady(isReady.trim());
book.setRooms(rooms);
book.setUser(user);
result = true;
}
return result;
}
...
bookDAO.create(book);
I'm getting
Column 'user_id' cannot be null
I am not sending 'user_id' in form but I have it stored in session BUT as integer.
So now when I am trying to force that int into the setUser I get an error that I can use only User objects there.
So my question is, are there any ways to convert Integer(which my id_user is) into the User?

You need to get User object from your database using the user_id in your session.
If you are using JPA entitymanager
User user = entityManager.find(User.class, user_id);
book.setUser(user);

You must select User by user_id from your database, or just
User user = new User();
user.setUserId(id_user);
book.setUser(user);

Related

Return null instead of org.hibernate.ObjectNotFoundException: Java

I have a table called ad_session which logs user sessions. I am using Java to get a list of all successful sessions from that table. I then loop through that list to get the user for each session (which is a foreign key to the ad_user table). I then get the client that belongs to that user, and I add the client to a list. However, one of the users no longer exists, so my code stops running and it gives throws the following exception:
org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [ADUser#76A5C22E6D2446A399AE9AD7C1DED0C7]
This is my original code:
List<Session> sessions = getAllSuccessfulSessionsInTable();
List<Client> clientsForThatDay = new ArrayList<>();
try {
for (Session session : sessions) {
//code fails when trying to get the non-existent user:
User user = session.getCreatedBy();
Client userClient = user.getClient();
clientsForThatDay.add(userClient);
}
} catch (Exception e) {
log.error("Error getting client from user: ", e);
}
I assumed that when getting a non-existent record, it would return null, so this is what I tried:
List<Session> sessions = getAllSuccessfulSessionsInTable();
List<Client> clientsForThatDay = new ArrayList<>();
//Create new user object to stand in place of the non-existent user
User deletedUser = new User();
deletedUser.setName("Deleted User");
//Create new client object to stand in place of the non-existent client
Client deletedUserClient = new Client();
deletedUserClient.setName("Unknown Client");
try {
for (Session session : sessions) {
//check is User is null, if it is, use the deletedUser object, otherwise, use the existing user
User user = session.getCreatedBy() == null ? deletedUser : session.getCreatedBy();
Client userClient = user.getName().equals("Deleted User") ? deletedUserClient : user.getClient();
clientsForThatDay.add(userClient);
}
} catch (Exception e) {
log.error("Error getting client from user: ", e);
}
However, it is not returning null, it's just throwing the exception and then stopping.
How can I get it to return null here so I can deal with the missing record without my code stopping?
Thanks in advance for any suggestions.
It seems that your database is missing a foreign key constraint.
This means that the table mapping User has a reference to a row in the table for Client that no longer exist.
This can only happen if a client has been deleted without updating the user table. The solution would be to add a foreign key constraint between the tables.
Keep in mind that if the data in your tables are not correct, when Hibernate loads the entity User, it will also believe there's a client. This means that User#getClient won't be null, and every place in the code where you have a check like user.getClient() == null is going to fail. A try-catch approach won't help you with this (unless you set the association to null in case of error, I guess).
The solutions I can think of:
Add the foreign key constraint (imho, the best solution)
Don't map the association, map client_id as an attribute and load the client using a second query or find (I would only do this if you cannot update the database)
class User {
#Column(name = "client_id")
Long clientId;
}
User user = ...
Client client = session.find(Client.class, user.getClientId());
You can load the client via session.find(Client.class, user.getClient().getId()) and set the association with the result:
User user = //...
Client client = session.find(Client.class, user.getClient().getId());
user.setClient(client);
Don't map the association at all in User, and run a native SQL query to load the client:
User user = ...
String sql = "select * from Client c join User u on c.id = u.client_id where u.id = :uid";
Client client = session.createNativeQuery(sql, Client.class)
.setParameter("uid", user.getId())
.getSingleResultOrNull();
You can pick what works best for you, but keep in mind that mapping an association without the foreign key constraint, will cause all sort of consistency issues.
I've decided to put option 3 only because, sometimes, people have some impossible situations at work, but I wouldn't recommend it.

One sql query to check for unique

I have a Spring Mvc application, in registration form i have an area for email and name
Before registering i check that all fields are unique in the DB with the following code in service layer (I'm using spring data)
#Override
public Optional<String> isUnuque(final Users user) {
if (this.repository.findByEmail(user.getEmail()) != null) {
return Optional.of("Your email is not unique");
} else if (this.repository.findByName(user.getName()) != null) {
return Optional.of("Your name is not unique");
}
return Optional.empty();
}
Then in controller i check if Optional is present. But with this code i make 2 requests to the DB, i can use native query like this to make only one request:
select * from users where name = 'dd' or email = 'ddd#mail.ru'
But how would i know which parameter is not unique name or email?
Thank in advance
BTW i solved this problem with the following code
#Override
public Optional<String> isUnuque(final Users user) {
final Users dbUser = this.repository.findByEmailOrName(user.getEmail(), user.getName());
if (dbUser != null) {
if (user.getEmail().equals(dbUser.getEmail())) {
return Optional.of("Not unique email");
} else {
return Optional.of("Not unique name");
}
}
return Optional.empty();
}
But if there are any sql query that can do exactly what i want without double checking in service layer please write it below
I'm not a java expert but as a database guy, I would say a better way would be to enforce the UNIQUE constraint on name and email in the table and handle the exception, which maintains the data integrity regardless of the application.
Another option is to get the count of emails and names with the given arguments.
SELECT count(CASE
WHEN name = :p_name
THEN 1
END) AS name_count
,count(CASE
WHEN email = :p_email
THEN 1
END) AS email_count
FROM users;
The COUNT function does not count nulls, so when condition in CASE is false( by default NULL), it adds 0 to the count. So, effectively the query would return name_count and email_count as 0 or 1 depending on the existing value, which you should be able to use in your code.
Union All can do this.
select 'name' from users where name = 'dd'
union all
select 'email' from users where name = 'ddd'#mail.ru

Change password for user in database

my question is to change password for user that is logged in the system. It prints out new password changed successfully but when i check it, the password remains the same and has not been changed. Is it because i use set.Password? Is there other ways? This code tries to retrieve Employee using username.
UPDATED : This question has been resolved by Alex's brilliant answer along with the other suggestions! Thank you all.
This is the method to invoke the remote controller
private void doChangePassword() throws UserNameNotFoundException, EmployeeNotFoundException {
Scanner scanner = new Scanner(System.in);
System.out.println("*** Administration Panel :: Change Password ***\n");
System.out.print("Enter username> ");
String username = scanner.nextLine().trim();
System.out.print("Enter current password> ");
String currentPassword = scanner.nextLine().trim();
System.out.print("Enter new password> ");
String newPassword = scanner.nextLine().trim();
System.out.print("Enter new password again> ");
String reenterNewPassword = scanner.nextLine().trim();
currentEmployee = employeeControllerRemote.retrievePasswordByUsername(username);
if (currentPassword.equals(currentEmployee.getPassword())) {
if (newPassword.equals(reenterNewPassword)) {
currentEmployee.setPassword(newPassword);
//Updated here
employeeControllerRemote.updateNewPassword(currentEmployee);
System.out.println("New Password changed successfully!\n");
} else {
System.out.println("New Password mismatched!\n");
}
}
else {
System.out.println("Wrong password, please try again later");
}
}
In another program, stateless session bean called employeeController. This method is implemented in employeeControllerRemote and local as well.
#Override
public Employee retrievePasswordByUsername(String username) throws UserNameNotFoundException {
Query query = em.createQuery("SELECT e FROM Employee e WHERE e.username = :inUsername", Employee.class);
query.setParameter("inUsername", username);
return (Employee) query.getSingleResult();
//Changed it according to suggestions
}
This is the new method that i created. I tried to use commit but it didn't work. I also tried to use persist and flush. But it says that it is a duplicate and there were illegal arguement errors. The flush did not work as well and the error code mentioned that there was nothing to flush.
I created this new method did not put it under retrievePasswordByUsername method because i think that it should not be there since it just retrieves it? So i created a new method below. It still does not work though.
#Override
public void updateNewPassword(Employee employee) {
//em.getTransaction().begin();
em.flush();
//em.getTransaction().commit();
}
Thank you all for your time! :)
You should not do the password updating in your doChangePassword() method, as it is in client side. It cannot update anything to database directly. It needs to do it via your stateless session bean.
So you should modify your method in stateless session bean to do the update job.
#Override
public void updatePasswordByUsername(String username, String password) throws UserNameNotFoundException
{
Query query = em.createQuery("SELECT e FROM Employee e WHERE e.username = :inUsername");
query.setParameter("inUsername", username);
//query.getSingleResult();
Employee employee = (Employee) query.getSingleResult();
employee.setPassword(password);
em.persist(employee);
}
Then you call this method in your client side through stateless session bean.
You may need to check the old password again in your stateless session bean in order to avoid attacks that bypass your client-side checking.
You need to persist the changed Entity/Data. entityManager.persist(employee); after you set the new PW.
Here are some other hints:
Casts shouldn´t be done. You can modify to this.
Query query = em.createQuery("SELECT e FROM Employee e WHERE e.username = :inUsername", Employee.class);
query.setParameter("inUsername", username);
return query.getSingleResult(); // now EMPLOYEE
Your workflow sould be:
Enter userName
Check if user exists (byName)
Input currentPassword, newPassword, newPasswordConfirm
Change the values
Persist your User/Employee so the change will be in DB, too. Without saving it in DB you just changed the local used Object-Instance.
you should use one of these "save, persist, update, merge, saveOrUpdate"
Try using the EntityManager.merge method - this is very similar.
employee.setPassword(newPassword);
em.merge(employee);

Using Spring Hibernate getHibernateTemplate().find to to select columns

I am using
List<USERS> user =
getHibernateTemplate().find("select uid, username,email from USERS");
to get three columns values from the users TABLE. But I can access no individual column value using the "user" object because the "user" type is an object type and I can't cast it to the USERS.
Is there any ways to use the "user" object and access individual columns value?
Why are you just querying selected columns - just get the whole row(s). Let me know if that helps.
If you are fetching only few columns, the hibernate template will return a list of object arrays.
Your example should look like this,
List<Object[]> userDetails =
getHibernateTemplate().find("select uid, username,email from USERS");
And you should know the first element is a integer and second, third are string and do cast on your own. This is very error prone ofcourse.
Thanks Nilesh and Sean for your suggestions. I always deal with the objects instead of individual columns. But this specific app works with other tables from another app which is not written in Java (That is why I am using USERS table not "User", because it is already created by another app) and is not using hibernate. I created a USERS class that implements UserDetails and has much less columns than the original app USERS table. When I get the whole object I get a formatting error that is why I tried using selected columns instead of the object.Anyhow I wrote this code and was able to get the individual columns:
List user=
getHibernateTemplate().find("select uid, username,email from USERS where uid<>0 AND obj_type=1");
List<USERS> l = new ArrayList<USERS>();
for (int i = 0; i < user.size(); i++) {
USERS du = new USERS();
Object[] obj = (Object[]) user.get(i);
Integer uid = (Integer) obj[0];
du.setUid(uid);
String username = (String) obj[1];
du.setUsername(username);
String email = (String) obj[2];
du.setEmail(email);
l.add(du);
}
My last question: isn't it more expensive to get the whole columns(the object) than getting the individuals ones?
Keep in mind it that...
getHibernateTemplate.find() method returns List of based on passed object.
Then after this you have to take List of Users then you have to separate all resulting object and after specified a object you can access attribute of it.
Its very easy..
If you have any query then tell me
I will try my best.
#Override
public Object findByNo(Object id) throws Exception {
List list = getHibernateTemplate().find(
"select book from Book book " +
"where book.id=?",id);
if (list.size() != 0) {
return list.get(0);
} else {
return new Book();
}
}
I'm guessing your db table is called USERS and the entity class is called User. If that is the case, then you should do something like this:
List<User> users = getHibernateTemplate().find("from User");
for(User user: users){
// you probably don't need the id, so I'll skip that
String email = user.getEmail();
String userName = user.getUserName();
// now do something with username and email address
}
If you use an ORM framework, deal with objects, not with Database Columns!
And about naming:
Java naming conventions suggest that a class name is in TitleCase (or more precisely UpperCamelCase), not UPPERCASE. Also, a class that represents a single user should be called User, not Users.
you can try something like this:
for (TemplateAttributes templateAttributes1 : templateAttributes) {
templateAttributes1.setTemplates(templates);
templateAttributes1.setCreateDate(new Date());
templateAttributes1.setCreateUser(ApplicationConstants.userName);
templateAttributes1.setLastModified(new Timestamp(new Date().getTime()));
templateAttributesNew.add(templateAttributes1);
}
templates.setTemplateAttributes(templateAttributesNew);
templates.setUpdateDate(new Date());
templates.setUpdateUser(ApplicationConstants.userName);
templates.setLastModified(new Timestamp(new Date().getTime()));
getHibernateTemplate().bulkUpdate("delete from TemplateAttributes where templateAttributePK.templates.id="+templates.getId());
getHibernateTemplate().update(templates);
Try this
List<USERS> user =(List<USERS>)(List<?>)
getHibernateTemplate().find("select uid, username,email from USERS");

HQL with a collection in the WHERE clause

I've been trying for the this whole a query who is officially giving me nightmares. The system is a user and contact management. So I have UserAccount, Contact and Phone.
UserAccount has a bidirectional one-to-many relationship with Contact and an unidirectional one on phone all mapped by a Set:
//UserAccount mapping
#OneToMany(targetEntity=PhoneImpl.class, cascade= {CascadeType.ALL})
#org.hibernate.annotations.Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private Set<Phone> phones = new HashSet<Phone>();
#OneToMany(targetEntity=ContactImpl.class, cascade={CascadeType.ALL}, mappedBy="userAccount")
#org.hibernate.annotations.Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private Set<Contact> contacts = new HashSet<Contact>();
Contact now has a one-to-many unidirectional with phones
#OneToMany(targetEntity=PhoneImpl.class, cascade={CascadeType.ALL})
private Set<Phone> phones = new HashSet<Phone>();
I'm writing a method to check the existence of the same number for the same contact of a particular user by the email unique field.
I know I could have overridden the equals and hashcode for that but since phone in a entity mapped by set I don't know at this moment how to do that. So I wanted to provide a method to rather check for that uniqueness for me before each entry on the contact page
public boolean checkForExistingPhone(String userEmail, String formatedNumber) {
List<Contact> result = null;
Session sess = getDBSession().getSession();
String query = "select Contact ,cphones.formatedNumber from Contact c inner join Contact.phones cphones where c.UserAccount.email = :email and cphones.formatedNumber= :number";
// try {
result = (List<Contact>) sess.createQuery(query)
.setParameter("email", userEmail)
.setParameter("number", formatedNumber).list();
// } catch (HibernateException hibernateException) {
// logger.error("Error while fetching contacts of email " + userEmail + " Details:" + hibernateException.getMessage());
// }
if(result == null)
return false;
else
return true;
}
I keep on having this error:
org.hibernate.hql.ast.QuerySyntaxException: Contact is not mapped [select
cphones.formatedNumber from Contact c inner join Contact.phones cphones where
c.UserAccount.email = :email and cphones.formatedNumber= :number].
I can't really figure out what happens and first i don't know how to treat collections in HSQ.thanks for reading
HQL query would be probably something along these lines:
select c
from Contact c
join c.phones cphones
where c.userAccount.email = :email
and cphones.formatedNumber = :number
Also you may want to handle results of query like this. The list() method returns always a list, never a null.
return !result.isEmpty();

Categories

Resources