Here is the method I wrote
public static <T> List selectOnCriteria(SessionFactory sessionFactory, int maxResults, T model)
{
List resultList=null;
session=sessionFactory.openSession();
Criteria criteria= session.createCriteria(model.getClass());
criteria.add(Example.create(model).ignoreCase());// only for exact search, uppercase and lowercase are both included in ignorecase
if(maxResults>0)
criteria.setMaxResults(maxResults);
resultList=criteria.list();
return resultList;
}
Here is one of my models
public class UserModel
{
#Id
private String username;
private String password;
private String company;
//getters and setters are also defined
}
Now Suppose That there is an entry in the table like this
Username: Chris
Password: Nolan
Company : Syncopy
If I populate my model with all these values then the resultList I obtain has 1 record.
However if only populate my model with username, ie Chris in this case, the resultlist I receive is always an empty ArrayList.
My Projects JPA Specification is 2.0, but if that is the issue, why does it return me the object in the first case and not the second.
Secondly , if that's the issue : is there any other way I can design a generic class that can take any model (of any type, with any number of fields populated)?
The last thing I want to do is to create a search method for all of my models.
Thanks and have a great day!
Related
I have a Couchbase-Document "Group" with a list of group-members-names. I want to query for all groups of one person. I managed to do it with N1QL ARRAY_CONTAINS - see in code example - but i hoped that i could generate the query from the method name as it is usual in Spring Data.
Any help is appreciated :)
I tried
public List<MyGroup> findAllByMembers(String member); and public List<MyGroup> findByMembers(String member); but they just return an empty list - i guess they try to match the whole "members" value and don't recognize it as a list -, no errors.
Code
My Document with a List field
#Data
#Document
public class MyGroup {
private String name;
private List<String> members = new ArrayList<>();
}
My Repository
#RepositoryDefinition(domainClass = MyGroup.class, idClass = String.class)
public interface MyGroupRepository extends CouchbaseRepository<MyGroup, String> {
//#Query("#{#n1ql.selectEntity} WHERE ARRAY_CONTAINS(members,$1) AND #{#n1ql.filter}")
public List<MyGroup> findAllByMembers(String member);
}
Expected
Given a "group1" with "member1" in members.
repository.findAllByMembers("member1"); should return ["group1"].
Couchbase is limited by the Spring Data specification. Unfortunately, we can't simply add new behaviors to it (if you switch to a relational database, it has to work with no breaking points). So, whenever you need to query something that has a N1QL specific function/keyword, you have to write a query via #Query
I have a SearchCriteria POJO class
public class SearchCriteria{
private int empId;
private String empName;
private String empAddress;
private String empDesignation,
:
:
//getter + setters
}
I have a returnAllEmployees method in other class
public List<Employees> returnAllEmployees (){
// makes a db call which has lot of joins and returns info for all the employees
}
now my question is I have to filter out the result of returnAllEmployees() based on the search criteria passed i.e. if empName field of searchcriteria is populated as "ABC", the filter list should contain details of all the employees as ABC.
Similarly, if search criteria contains empName="ABC" and empDesignation="engineer", it should filter out the list containing all the employees having name abc and designation as engineer
I know it is possible by using if-else but that would create a lot of lines of codes
Your best solution is to use Java 8 streams. They are perfect for this:
List<Employee> listOfEngineersCalledFred = getAllEmployees().stream()
.filter(emp -> emp.getName().equals("Fred"))
.filter(emp -> emp.getDesignation().equals("Engineer"))
.collect(Collectors.toList());
A technique that I personally find useful and neat is to add static methods that return predicates instead of using getters:
class Employee {
public static Predicate<Employee> hasName(String name) {
return emp -> emp.name.equals(name);
}
}
These can then be used, for example, to find all employees not call Fred:
streamAllEmployees()
.filter(Employee.hasName("Fred").negate())
...
Which seems neater and more deliberate than exposing the field with a getter.
You also might consider converting your getAllEmployees to streamAllEmployees:
public Stream<Employee> streamAllEmployees() {
return employeeList.stream();
}
Then you are telling the user they can do things with the employee objects in the list rather than the list itself.
The nice thing about returning it as a stream is that once you have filtered it you can easily count, group, sort, remove duplicates, get first n etc. You can even trivially convert it to use multiple threads if you are filtering large numbers of items.
For example:
Map<String, Employee> employeesByDesignation = streamAllEmployees()
.collect(Collectors.groupingBy(emp -> emp.getDesignation()));
They are very powerful and worth learning and using.
I've been using spring and hibernate for this past few weeks and I've always been learning something new there.
Right now I've got a problem that I want to solve with Projections in Hibernate.
Suppose there is a model Person and that model has many Car. The following are how the class definitions roughly gonna look like:
public class Person implements java.io.Serializable {
private Integer id;
private String name;
private List<Car> cars;
private Integer minYear; // Transient
private Integer maxYear; // Transient
}
public class Car implements java.io.Serializable {
private Integer id;
private Integer year;
}
The problem here is I want to get the minYear (maxYear) of each Person to be filled by the earliest year (latest year) of the cars they have.
Later I found a solution to use Projections but I stumbled upon org.hibernate.QueryException: could not resolve property: minYear of: model.Person and here is the code of the db operation:
Criteria criteria = sessionFactory.getCurrentSession().createCriteria("model.Person");
criteria.add(create(personInstance));
criteria.createAlias("minYear", "minYear");
criteria.setProjection(Projections.min("cars.year").as("minYear"));
Is there anyway to store the aggregation value in transient method using Projections because I just want to avoid using plain SQL and HQL as much as possible.
Never mind, I've found the solution.
First we need to create alias of the associated object like so
Criteria criteria = sessionFactory.getCurrentSession().createCriteria("model.Person");
criteria.createAlias("cars", "cars");
Select the needed using Hibernate Projections
ProjectionList projections = Projections.projectionList();
projections.add(Projections.property("id").as("id"));
projections.add(Projections.property("name").as("name"));
projections.add(Projections.property("cars").as("cars"));
Group the result based on the root entity (in this case using its id, Person.id), this is needed especially when used with aggregation to group the aggregation
projections.add(Projections.groupProperty("id"));
Use the aggregate function
projections.add(Projections.min("cars.year").as("minYear"));
projections.add(Projections.max("cars.year").as("maxYear"));
Set the projection
criteria.setProjection(projections);
Use result transformer AliasToBeanResultTransformer to map the result fields (as specified in step 2 & 4) to the POJO
criteria.setResultTransformer(new AliasToBeanResultTransformer(Person.class));
Get the result
List<Person> results = (List<Person>) criteria.list();
I am using java 1.6. I have a Employee model as shown below:
private String id;
private String firstName;
private String lastName;
private String phoneNumber;
//getters and setters
The List<Employee> contains all the employee data fetch from the DB.
I need to search for one or more employees present within the List<Employee> (something like a employee search functionality, search has to be done on the List<Employee> rather than another DB hit with search criteria). As of now, I don't want any DB hit for searching the employee from the List<Employee>. But if it becomes complicated then I have to go for the db hit.
Right now whatever I have thought of is a sluggish logic like: Iterate through the List<Employee> and for each Employee keep on searching for the values of search criteria, if it matches then add it to a new List<Employee> (this will give me the search result).
I want to know if there is some optimal way of achieving the same. Please let me know about this.
Sorting: http://docs.oracle.com/javase/6/docs/api/java/util/Comparator.html
class EmployeeComparator implements Comparator<Employee>{
public int compareTo(Employee o1,Employee o2){
return o1.lastName.compareTo(o2.lastNam);
}
}
and:
Collections.sort(listOfEmplyees, new EmplyeeComparator);
But I don't understand, how this will help by your searching. At least it is sorted now.
I have this class:
public class DBRow {
public String url;
public String title;
public static Hashtable<String, Integer> words;
public Vector<String> keywords;
}
What I must do is store many instances of this class in a database. I'm using Hibernate and JPA to get the job done. Using JPA I've come so far (really not far):
#Entity
#Table(name="MAIN_TABLE")
public class DBRow {
#Column(name="url")
public String url;
#Column(name="title")
public String title;
public static Hashtable<String, Integer> words;
public Vector<String> keywords;
}
I want my database to have 3 tables - MAIN_TABLE - auto-icremented id as primary key, url and title; HASH - containing a key-value pair from the Hashtable<String, Integer> and id to refer to which instance of DBRow class it belongs (and also to relate to the MAIN_TABLE); VECTOR - pretty much the same story like HASH but with a Vector<String>. So what I'm asking is hot to map the hashtable and the vector, using JPA to get it done?? I've been trying to find a way to do this but haven't found one so far... or maybe I'm not on the right way! Any suggestions are welcome. Thank you in advance.
This is not possible with JPA 1.0 (at least, not with standard annotations) and since you did not mention your JPA provider, I will only cover JPA 2.0. In JPA 2.0, the #ElementCollection annotation can be used to map a collection of basic types or embeddable objects.
Below some examples taken from EclipseLink/Development/JPA 2.0/new collection mappings:
Example 1 - An element collection representing a basic collection mapping.
#ElementCollection
#Column(name="DESIGNATION")
// CollectionTable will default in this case, Entity name + "_" + attribute name
// JoinColumns will default in this case which are different from BasicCollection collection table default
private Collection<String> designations;
Example 2 - An element collection representing an basic map mapping.
#ElementCollection
#MapKeyColumn(name="Q_DATE")
#Column(name="QUOTE")
#CollectionTable(name="EXPERT_QUOTES", joinColumns=#JoinColumn(name="EBC_ID"))
public Map<Date, String> getQuotes() {
return quotes;
}
Now, I second one of the comment to your question and I would consider using "moderner" data structure like ArrayList and HashMap.
Also note that static (and final) entity fields are always considered to be transient i.e. can't be persisted.