I need a User entity that has a primary key ID and two unique not null (not primary) keys: email and username. Then I receive a username and an email and I need to retrieve a User entity that has either that received username or email.
I see that #NaturalId makes a column unique and not null. The problem is that when you have more than one #NaturalId, Hibernate creates a unique index on the pair (email, username), meaning that it won't be any rows with same pair (email, username) but it may appear one that has same email but different username.
Can it be solved with #NaturalId? If is possible how would I retrieve the entity matching either the received username or email but not necessarily both.
If it's not possible, would this be the optimal solution?
final Session session = HibernateUtil.openSession();
final CriteriaBuilder builder = session.getCriteriaBuilder();
final CriteriaQuery<User> criteria = builder.createQuery(User.class);
final Root<User> userRoot = criteria.from(User.class);
criteria.where(builder.equal(userRoot.get("username"), username));
/* How do I join the criteria for username and email using ||?
So that it gets me an entity that has that email or username. */
final User foundUser = session.createQuery(criteria).uniqueResult();
your query will like:
Session session = HibernateUtil.getSession();
Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.disjunction()
.add(Restrictions.eq("username", value))
.add(Restrictions.eq("email", value)));
User user = (User)criteria.setMaxResults(1).uniqueResult();
Hql query :
Query query = session.createQuery("from User as s where s.username = :userInputValue or s.email =:userInputValue");
query.setParameter("userInputValue", userInputValue);
query.setMaxResults(1);
User user = (User) query.uniqueResult();
you can't get unique result with your given result, because as you have mentioned, it may possible we have 2 rows which one of them have a username like "Jom#test.com" and another row have email "Jom#test.com".
So it's possible scenario to not get unique value, for fix it you need make a 2 unique constraint of any of filed, basically you need 2 unique filed in one row.
Related
I am confused about the above relationship.
My Oracle DB Tables:
xd_Users: user_id (pk), client_id (fk), name, doj, email, dol
xd_Managers: manager_id (pk), user_id (fk)
Corresponding Java Entities User and Manager relate to the above two tables respectively. Manager and User are separate, not related by inheritance, and have fields that correspond to the DB tables.
In my application, a Manager has to be a User.
I am writing the a(n as yet unfinished) method (in a class called PersistService) to retrieve a list of users who are managers.
public static ArrayList<User> getManagersForClient(Client client) {
Long clientId = client.getClientId();
EntityManager em = getEntityManager();
String sqlQuery = "SELECT u FROM XD_USERS u, XD_MANAGERS m WHERE u.CLIENT_ID = :clientId";
TypedQuery<User> query = em.createQuery(sqlQuery, User.class);
query = query.setParameter("clientId", clientId);
ArrayList<User> clientUsers = (ArrayList<User>) query.getResultList();
for (User user : clientUsers) {
}
return clientUsers;
}
The pseudo-sql query I constructed was (:client_id at the end is just the java variable, hence the pseudo-sql):
select * from users u join managers m on u.user_id = m.user_id where u.client_id = :client_id;
I am having trouble converting this to a valid JPQL query. I don't understand how to think about solving this. In particular, the relationship between the identification variable, the single-valued relationship field, the collection-valued relationship field and the persistent field is very confusing. And I am even more confused by this post. Please help!
If you have coded the related entities correctly then your sql select query is something like this in jpql (according to the structure of related tables you gave):
select u.userId,u.name,u.doj,u.email, u.dol, m.managerId
from User u
join u.manager m
where u.clientId = :client_id;
Let's say I have two tables Task and Company. Company has columns id and name. Task has two columns customerId and providerId which link back to the id column for Company.
Using Querydsl how do I join on the Company table twice so I can get the name for each company specified by the customerId and providerId?
Code that maybe explains better what I'm trying:
Configuration configuration = new Configuration(templates);
JPASQLQuery query = new JPASQLQuery(this.entityManager, configuration);
QTask task = QTask.task;
QCompany customer = QCompany.company;
QCompany provider = QCompany.company;
JPASQLQuery sql = query.from(task).join(customer).on(customer.id.eq(task.customerId))
.join(provider).on(provider.id.eq(task.providerId));
return sql.list(task.id, customer.name.as("customerName"), provider.name.as("providerName"));
Which generates SQL:
select task.id, company.name as customerName, company.name as providerName from task join company on company.id = task.customerId
And I'd really like it to be:
select task.id, customer.name as customerName, provider.name as providerName from task join company as customer on customer.id = task.customerId join company as provider on provider.id = task.providerId
I couldn't figure out how to alias the table I was joining so I could distinguish between customer and provider names. I tried doing new QCompany("company as provider") but that didn't work. Anyone know how one can do this?
If you need to variables just do the following
QCompany customer = new QCompany("customer");
QCompany provider = new QCompany("provider");
Reassignment of the default variable QCompany.company doesn't help
I have a table Users
Id(key) | username | some other cols...n
and a table Tokens:
userID, Token (k)
userID in Tokens is defined as being the foreign key from users.id.
What i want to do is to be able to : Given a Tokens.token, get the col info from Users.
the mysql command in SQL is like such:
select a.* from users a left join tokens b on a.User_Id = b.userId and b.userId = 1;
(i dont know if the above is optimal...but it returns what i want)
How would i replicate that in JPQL?
The simple select fetch command i am familar with is: (other than using the built in one)
String qlString = "Select p from Tokens p WHERE p.token=:token";
TypedQuery<Tokens> query = this.entityManager.createQuery(qlString,Tokens.class).setParameter("token", token);
When you use JPA, you don't mind for table and columns, you use Entities and Relations, the query must be:
select u.info from User u join u.tokens t where t.token = :token
This assumes:
#Entity class User {
#OneToMany List<Token> tokens;
String info;
}
#Entity class Token {
String token;
}
You start from User, then go with your attribute tokens to the Token entity, and filter for the Token attribute.
To get the list you use:
List<String> infos = entityManager.createQuery(YOUR_QUERY).list();
I understand some might simply answer this question with "Why didn't you just Google it"... But I did, and the more I researched this the more confused I got. I'm trying to query my database with Hibernate, the query has a 'where' clause.
Now creating a database entry is easy enough, in the case where I have a 'User' class, I simply do this:
// Gets a new session
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
// Creates a new User object
User user = new User("John", "p#55w0rd*", "john#doe.com");
// Save and commit
session.save(user);
session.getTransaction().commit();
But what do I do when I what to for instance
select * from Users where id = '3';
My Google searches pointed to something called HQL, which makes me wonder why I couldn't of just used straight JDBC then. Also it doesn't seem very object oriented. And then there's something like
session.createCriteria(.......
But I'm not sure how to use this.. Any help? Thanks guys.
When you use Native Query (non HQL ) you need to tell hibernate explicitely to handle it like below :
In below query createSQLQuery is special function to handle native sql's
String sql = "SELECT * FROM EMPLOYEE WHERE id = :employee_id";
SQLQuery query = session.createSQLQuery(sql);
query.addEntity(User.class);
query.setParameter("employee_id", 3);
List<User> results = query.list();
This can be done using criteria as well for that following is good starting point:
Criteria criteria = sess.createCriteria( User.class);
List<User> users= criteria.list();
http://www.developerhelpway.com/framework/hibernate/criteria/index.php
First of all, you need a hibernate.cfg.xml which contains properties for hibernate. This is e.g url, username and password, the driver and dialect. This file is placed in a package called resources.
You have to choose between using Hibernate Annotations example
or using hbm.xml files example
This is how you tell hibernate what your database is like. It wil automatically create queries for you based on how you annotates or defines in e.g user.hbm.xml.
Create a HibernateUtil.java class which holds the session factory.
You can fetch data from the database with
Criteria crit = getSessionFactory().getCurrentSession().createCriteria(User.class);
Example using queries:
List<?> hibTuppleResultList = currentSession.createQuery(
"from Person p, Employment e "
+ "where e.orgno like ? and p.ssn = e.ssn and p"
+ ".bankno = ?")
.setString(0, orgNo).setString(1, bankNo).list();
for (Object aHibTuppleResultList : hibTuppleResultList)
{
Object[] tuple = (Object[]) aHibTuppleResultList;
Person person = (Person) tuple[0];
hibList.add(person);
}
In the end all I really wanted was to know that if you don't want to use HQL you get something called 'Criteria Queries', and that in my case I'd do something like this:
Criteria cr = session.createCriteria(User);
cr.add(Restrictions.eq("id", 3));
List results = cr.list();
Me: "Thanks!"
Me: "No problem :)"
PS - we can really delete this question.
Query q = session.createQuery("from User as u where u.id = :u.id");
q.setString("id", "3");
List result = q.list();
Query with Criteria:
Criteria cr = session.createCriteria(User.class);
List results = cr.list();
Restrictions with Criteria:
Criteria cr = session.createCriteria(User.class);
cr.add(Restrictions.eq("id", 3));
// You can add as many as Restrictions as per your requirement
List results = cr.list();
You could also use it like this
List results = session.createCriteria(User.class).add(Restrictions.eq("id", 3)).list();
Some example for Crieteria Rsetriction query
Criteria cr = session.createCriteria(Employee.class);
// To get records having salary more than 2000
cr.add(Restrictions.gt("salary", 2000));
// To get records having salary less than 2000
cr.add(Restrictions.lt("salary", 2000));
// To get records having fistName starting with zara cr.add(Restrictions.like("firstName", "zara%"));
// Case sensitive form of the above restriction.
cr.add(Restrictions.ilike("firstName", "zara%"));
// To get records having salary in between 1000 and 2000
cr.add(Restrictions.between("salary", 1000, 2000));
// To check if the given property is null
cr.add(Restrictions.isNull("salary"));
// To check if the given property is not null
cr.add(Restrictions.isNotNull("salary"));
// To check if the given property is empty
cr.add(Restrictions.isEmpty("salary"));
// To check if the given property is not empty
cr.add(Restrictions.isNotEmpty("salary"));
You can create AND or OR conditions using LogicalExpression restrictions as follows:
Criteria cr = session.createCriteria(Employee.class);
Criterion salary = Restrictions.gt("salary", 2000);
Criterion name = Restrictions.ilike("firstNname","zara%");
// To get records matching with OR condistions
LogicalExpression orExp = Restrictions.or(salary, name);
cr.add( orExp );
// To get records matching with AND condistions
LogicalExpression andExp = Restrictions.and(salary, name);
cr.add( andExp );
List results = cr.list();
I think this will help you
Using following code I can successfully retrieve address fields of a user, to do that I need to define all its fields using Projection. Imagine address has 100 fields, in this case I have to define all of them.
I am wondering if I can return just address object of customer without defining all its fields in Proposition?
I know I can retrieve id of address and use that to retrieve its object, but I am wondering if there is ano other method rather than this or defining all its fields.
Hibernate
.....
Criteria cre = session.createCriteria(User.class, "user")
.createAlias("user.address", "addr");
cre.add(Restrictions.eq("user.id", ID));
ProjectionList pl = Projections.projectionList();
pl.add(Projections.property("addr.id").as("id"));
pl.add(Projections.property("addr.unit").as("unit"));
.......
cre.setProjection(pl);
Address address = (Address) cre.list().get(0);
I used the following as well but it runs into error (could not resolve property: addr of: com.myProject.User)
pl.add(Projections.property("addr").as("address"));
Java
#Entity
public Class User {
#Id
#GeneratedValue
private long id;
#OneToOne
private Address address;
...
}
Use JPQL/HQL:
select a from User u join u.address a where u.id = :userId
The Criteria API is more limited than JPQL, and can't select any other entity than the root entity. It shouldn't be used if the query doesn't have to be dynamically composed. Of course, if the association is bidirectional, you can simply use
select a from Address a where a.user.id = :userId
or its equivalent Criteria:
Criteria c = session.createCriteria(Address.class, "a");
c.createAlias("a.user", "u");
c.add(Restrictions.eq("u.id", userId));
If the result you pull in from a query will match the fields of a DAO you have defined. I would just type-cast the result from an hql or native SQL query.
Select *
From Address a
where a.id = :userid
Address addrObject = (Address) query.uniqueResult();
Do like this
Criteria criteria = session.createCriteria(User.class, "user")
.createAlias("user.address", "addr")
.add(Restrictions.eq("user.id", userId))
.setProjection(Projections.property("addr"));
Address address = (Address) criteria.list().get(0);
Couple of options:
use lazy="false" for Address object. If you have to use lazy=true for some reason, you can run this query in a separate session and override the lazy behavior in that session.
Use the database specific query to get a list of field names and then dynamically generate Projections by looping through the field names.
For example,
In mysql
SHOW COLUMNS FROM Address
In postgres
SELECT * FROM information_schema.columns
WHERE table_schema = your_schema
AND table_name = your_table
I hope this helps.