Want to modify Hibernate criteria using entity

In my example I created a Hibernate criteria only using my entity object "contract".

     @Transactional
    public static List<Contract> findAllContractsPerContract(Contract contract) {
        EntityManager e = entityManager().getEntityManagerFactory().createEntityManager();
        Session session = e.unwrap(Session.class);
        Example contractExample = Example.create(contract).excludeProperty("fromDate").excludeProperty("endDate");;
        Criteria c = session.createCriteria(Contract.class).add(contractExample);
        // here some restriction can be done. (in a dynamic way like equlas/greater/less...)
        List<Contract> list = c.list();
        return list;
    }

The contract object has many parameters. In this case all the parameters of contract are searched by equals. So, if the parameters are matching, I get the right results.

But now I want do add some criteria to some parameters of contract object. Two parameter for example are: "fromDate" and "endDate". Its possible to modify the existing criteria like >= fromDate and <=endDate (or between). The criteria should also be dynamically.

I Know that I can add some criteria at the end of this line:

Criteria c = session.createCriteria(Contract.class).add(contractExample);

But this is only a addition to the existing query. Is there a solution or another technical way to solve the problem?

Thanks for input.

Update 1

Request without Operands:

allRequestParams={"v00Datvon":"09-07-2014","v00Datbis":"09-07-2014","v00Saicode":{"saiCode":"SO02"}}

Request with Operands example

allRequestParams={"v00Datvon":"09-07-2014","operand":"less","v00Datbis":"09-07-2014","operand":"greater","v00Saicode":{"saiCode":"SO02","operand":"equals"}}

In Controller I get the JSON String like this:

    @RequestMapping(value = "/", method = RequestMethod.GET, headers = "Accept=text/plain")
    public ResponseEntity<String> getVertagFromSearch(@RequestParam String allRequestParams, ModelMap model) throws JsonProcessingException{
//do stuff
}

Update 2

One other big problem is the subdomainobject of contract. v00Saicode depends on contract. Same problem with the dates. Without parsing the JSON String to contract object, I lose the transformation of Calender class. I really stock how I should react in the controller. Has anybody a solution.

Solution

This is my way to do all the parts in a dynamic way.

The request got an additional part for the operators.

The Controller received the String like this:

@RequestMapping(value = "/", method = RequestMethod.GET, headers = "Accept=text/plain")
public ResponseEntity<String> getVertagFromSearch(@RequestParam String allRequestParams,@RequestParam String operators, ModelMap model) throws JsonParseException, JsonMappingException, IOException, IntrospectionException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    HashMap<String, String> operatorsMap = new ObjectMapper().readValue(operators, HashMap.class);
    Contract contract = Contract.fromJsonToContract(allRequestParams);
    List<Contract> list = Contract.findAllContractsPerContract(contract, operatorsMap);
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Type", "application/json");
    return new ResponseEntity<String>(Contract.toJsonArray(list),headers,HttpStatus.OK);
}

The DAO and the call to a helper class

      public static List<Contract> findAllContractsPerContract(Contract contract, Map<String, String> operatorMap) throws IntrospectionException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    EntityManager e = entityManager().getEntityManagerFactory().createEntityManager();
    Session session = e.unwrap(Session.class);
    Criteria criteria = session.createCriteria(Contract.class);
    criteria = CriteriaBuilder.buildCriteria(contract, criteria, operatorMap);
    List<Contract> list = criteria.list();
    return list;
}

The Criteria Builder helper class and code of @Jeff answer:

public static Criteria buildCriteria(Object object, Criteria criteria, Map<String,String> operatorMap) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException{
     BeanInfo vertagInfo = Introspector.getBeanInfo(Contract.class);
        for(PropertyDescriptor propertyDescriptor : vertagInfo.getPropertyDescriptors()){
            String propertyString = propertyDescriptor.getName();
            Object value = propertyDescriptor.getReadMethod().invoke(object);
            if(propertyString.equals("class")||value==null){
                continue;
            }
            String operator = operatorMap.get(propertyString);
            if(operator==null){
                operator="EQ";
            }
            criteria.add(Comparison.valueOf(operator).convert(propertyString, value));
        }
    return criteria;
}

Answers


Grab the values for from date and end date from your Contract instance and then set them to null in that instance. Example.create(contract) will not add the default eq restriction for those null fields, and you can then follow @Pracede's code to do the ge and le restrictions.

You could probably also call excludeProperty() on your Example instance for the date fields you are going to manually add. That's probably the more elegant way to go.

Update

If you need this to build criteria dynamically based on input from the user, then query by example probably isn't the way to go. Create an enum that can handle all the comparison types you care about and return the appropriate Criterion comparison for each type:

public enum Comparison {
    EQ {
        @Override
        public Criterion convert(String propertyName, Object propertyValue) {
            return Restrictions.eq(propertyName, propertyValue);
        }
    },
    LE {
        @Override
        public Criterion convert(String propertyName, Object propertyValue) {
            return Restrictions.le(propertyName, propertyValue);
        }
    },
    LIKE {
        @Override
        public Criterion convert(String propertyName, Object propertyValue) {
            return Restrictions.like(propertyName, propertyValue);
        }
    };

    public abstract Criterion convert(String propertyName, Object propertyValue);
}

Then when you're processing your JSON input in the controller, get the correct enum type for each comparison, and let it give you the restriction you need:

Criteria c = session.createCriteria(Contract.class);
for each name, value, comparator in JSON data*
    c.add(Comparison.valueOf(comparator).convert(name, value)

*Note: I'm not suggesting you move DAO code up into the controller; instead of passing a Contract instance to your DAO, pass an array of objects that represent the data from JSON input.


Did you try this :

 if(fromDate!= null && endDate=null) {
                criteria.add(Expression.ge("date", fromDate));

                criteria.add(Expression.le("date", endDate));
            }

You have to add the next criteria to the current one.


Need Your Help

HTML Input Checkbox return 'On' instead of 'True' when submitting form

javascript jquery html

I have a MVC3 app using Project Awesome (http://awesome.codeplex.com/), but I am getting a weird behaviour on checkboxes. I have the following simple Html within a Modal popup &lt;input type="check...

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.