I'm trying to create "search engine" on my DB.
I have a table with Id, Name and Description.
When I have an Id I can get the record with this Id by find().
But if I want to get records by Name or Description how can I do that? Did I've to set the Name as index?
Thanks.
As a general rule, if you have to frequently query a table by one of its fields and the table contains many records, it might be a good idea to create an index for that field in the database.
About the other question: if you need to get records by name, by description or by some other field and you're using JPA, then use the JPQL query language. For example, assuming that the entity is of type MyEntity (with fields id, name, description) the following query will return a list of entities with name aName:
EntityManager em = ... // get the entity manager
Query q = em.createQuery("SELECT me FROM MyEntity me WHERE me.name = :name");
q.setParameter("name", aName); // aName is the name you're looking for
List<MyEntity> results = (List<MyEntity>) q.getResultList();
Read more about the Java Persistence API in the tutorial.
Related
I have 2 tables in MySQL database: user and user_additional_details with columns described below.
User
id (auto increment)
userId (unique)
first name
last name
phone
email
User Additional Details
id (auto increment)
userId (matches userId in User)
personalPhone
personalEmail
Table user_additional_details contains 0 or 1 row for each userId in user table.
However, database does not have a foreign key constraint defined. Ideally, columns from user_additional_details should have been added as nullable columns in user table, but that was not done for some unknown reason. Now I need to define the entity for following query.
select user.userId, user.phone, user_a_d.personalPhone
from user
join user_additional_details as user_a_d
on user.userId = user_additional_details.userId
I tried defining JPA entities for the tables, but not able to figure out how to create an entity that uses columns from different tables.
It seems like the SecondaryTable annotation is what you are looking for
Specifies a secondary table for the annotated entity class. Specifying
one or more secondary tables indicates that the data for the entity
class is stored across multiple tables.
Here you find a detailed example of how to use it - http://www.thejavageek.com/2014/09/18/jpa-secondarytable-annotation-example/
Create UserEntity (with all the columns from User table) and UserAdditionalDetailsEntity(with all the columns from user_additional_details table). I assume you are aware how to create JPA entities and map them to database table.
I hope you would have create entity manager factory object in your spring configuration file. With the help of that create entity manager object .
Once EntutyManager Object is created:
Query q= em.createQuery("select user.userId, user.phone, userDetails.personalPhone
from UserEntity user
join UserAdditionalDetailsEntity as userDetails
on user.userId = userDetails.userId");
List<Object[]> resultList= q.getResultList();
Once you get resultList you can iterate over the list of object array and get data.
Each index of the resultList will contain the object array representing one row
Keep in mind that field name mentioned in query should be same as the one mentioned in your JPA Entites.
I am using Spring JPA and in order to ad a List of String to my Entity I am using #ElementCollection as below.
#ElementCollection
private Map<Integer, String> categories;
When I use this it generates a table called subscription_categories this contains the following columns subscription(varchar), catergories(varchar) and caterogies_key (int)
If I use my SQL tool on my desktop I can query this table fine with the following
select `subscription_categories`.`subscription` from `subscription_categories` where `subscription_categories`.`categories`='TESTING';
However, when I attempt to use this in Spring Data it fails with a "... not mapped" error
Here are a few attempts below:
#Query("select s.subscription from subscription_categories s where s.categories = ?1")
List<Subscription> findUsernameByCategory(String category);
#Query("select s.subscription from categories s where s.categories = ?1")
List<Subscription> findUsernameByCategory(String category);
Both return the same error.
Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException:
categories is not mapped
My question is this:
How can I query the table created by the #ElementCollection?
You can't directly query from #ElementCollection. You should query base entity (I assume its name is Subscription).
#Query("select s from Subscription s where s.categories = ?1")
List<Subscription> findUsernameByCategory(String category);
If you want query by key, then use
#Query("select s from Subscription s where index(s.categories) = ?1")
List<Subscription> findUsernameByCategoryKey(Integer key);
I'd also side with #talex on this and argue that you need to base your query on the parent/container/base object of the #ElementCollection.
In my experience following query should suffice:
#Query("select category from Subscription subscription inner join subscription.categories category")
Side-note: Querying subscription_categories seems to be the wrong path, since this table is part of a different layer (the database layer in Sql/Jpql), while the query should be formed on the Hibernate layer (hql), which uses your entity/class-names as references.
I have used Upper-case class names, instead of lower-case table names.
I have a 3 tables:
Item: item_id (pk), short_description, ...
SupplierItem: item_id (fk), supplier_id (fk), vendor_product_number, ...
Supplier: item_supplier (pk), name, ...
Relation between Item and Supplier is many to many. SupplierItem is
intermediate table.
I want use VO and DAO.
How to design this in VO (Java)?
After, How can I do the following query in java code.
select i.item_id, i.short_description, s.vendor_product_number as FONUA_PRODUCT_CODE
from item i
left join supplier_item s
on i.item_id=s.item_id
where ((i.item_id=:item_id) OR :item_id IS NULL)
and i.parent_item_id is null
order by vendor_product_number DESC"
I still do not understand the concept in use VO and DAO.
Thanks
DAO would be the java file where you define your query and get the results of the query call on the database.
The results from the query will be saved by setting them as values to the properties of a particular VO.
For Example:
Your query returns ,
item_id, short_description, vendor_product_number
So let us say that you will have to create another java file say ItemVO.java and declare the particular properties of the ItemVO object,
For Ex:
private String itemId;
private String shortDescription;
private String vendorShortNum;
/*Define your getters and setters*/
In the DAO file you will have to map the query results to the VO file's objects.
ItemVO itemVO= new ItemVO();
itemVO.setItemId(/*the particular column value from the query result*/);
itemVO.setShortDescription(/*the particular column value from the query result*/);
itemVO.setVendorShortNum(/*the particular column value from the query result*/);
I have a named query as below;
#NamedQuery(name = "MyEntityClass.findSomething", query = "SELECT item FROM MyTable mytbl")
Now I want to append dynamic sort clause to this query (based on UI parameters)
Can I get an example using JPQL for doing the same (like how to set a dynamic ORDER BY in the Entity class)
I have already tried using CriteriaQuery, but was looking for a JPQL implementation now.
NamedQueries are by definition NOT dynamic, it is not correct to change them programmatically.
So the way to go is to create a JPQL query (but not a named query) like this:
TypedQuery<MyEntity> query = em.createdQuery("SELECT item FROM MyEntity item ORDER BY "+sortingCol, MyEntity.class);
On the other hand, if you REALLY want to use the named query, you could do that the following way:
#NamedQuery(name = "MyEntityClass.findSomething", query = MyEntity.NAMED_QUERY)
#Entity
public class MyEntity {
public static final NAMED_QUERY= "SELECT item FROM MyTable mytbl";
//+your persistent fields/properties...
}
//and later in your code
TypedQuery<MyEntity> query = entityManager.createQuery(MyEntity.NAMED_QUERY + " ORDER BY " + sortingCol, MyEntity.class);
Complementing for JPA 2.1
As of JPA 2.1 it is possible to define named queries programmatically.
This can be achieved using entityManagerFactory.addNamedQuery(String name, Query).
Example:
Query q = this.em.createQuery("SELECT a FROM Book b JOIN b.authors a WHERE b.title LIKE :title GROUP BY a");
this.em.getEntityManagerFactory().addNamedQuery("selectAuthorOfBook", q);
// then use like any namedQuery
Reference here
This can be useful, for instance, if you have the orderby field defined as a application parameter. So, when the application starts up or on the first run of the query, you could define the NamedQuery with the defined OrderBy field.
On the other side, if your OrderBy can be changed anytime (or changes a lot), then you need dynamic queries instead of NamedQuery (static). It would not worth to (re)create a NamedQuery every time (by performance).
#NamedQuery
Persistence Provider converts the named queries from JPQL to SQL at deployment time.
Until now, there is no feature to create/update the query with #NamedQuery annotation at runtime.
On the other hand, you can use Reflection API, to change the annotation value at runtime. I think It is not solution, also it is not you wanted .
em.createQuery()
Persistence Provider converts the dynamic queries from JPQL to SQL every time it is invoked.
The main advantage of using dynamic queries is that the query can be created based on the user inputs.
Environment: JPA 1, Hibernate 3.3.x
I have an JPA entity class (User), how do I selectively fetch member variables say (first_name, last_name) instead of fetching all user attributes using the JPA api.
Do you mean something like this (and in that case, the result of your query will be an Object[]):
SELECT u.firstName, u.lastName FROM User u
Alternatively, you could use a constructor expression in the SELECT clause:
SELECT NEW com.acme.example.UserDetails(u.firstName, u.lastName) FROM User u
The class used in the NEW is not necessarily an Entity, it just has to provide a proper constructor.
If you query for more columns you'll get an object result which you'll have to cast to an object array to retrieve values. Better is to create a viewObject class in which you directly store the results:
select new full.package.name.UserView(u.firstName, u.LastName) from User u
where UserView looks like:
class UserView {
String firstName, String lastName;
// getters, setters/constuctor
}