Custom criteria in hibernate
In a previous article, I talked about how to teach Hibernate to store custom data types. Now let's try to use this data when filtering samples. We will declare the result we want to get:
First, we write a universal implementation of the search criteria. To do this, make a small change to the StringArrayCustomType.nullSafeGet and StringArrayCustomType.nullSafeSet methods, namely, surround the value stored in the column with spaces. (Changes in lines 7 and 25)
Now we carefully implement the org.hibernate.criterion.Criterion interface.
Well, that's all. Now we can save and filter custom types.
______________________
- String filteringTag = "habr";
- Session session = ...;
- Criteria criteria = session.createCriteria(StringArrayContainer.class);
- criteria.add(new StringArrayContainsCriterion("tags", filteringTag));
- List containers = criteria.list(); //Получаем список контейнеров, содержащих тег "habr"
- ...
First, we write a universal implementation of the search criteria. To do this, make a small change to the StringArrayCustomType.nullSafeGet and StringArrayCustomType.nullSafeSet methods, namely, surround the value stored in the column with spaces. (Changes in lines 7 and 25)
- @Override
- public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException {
- String value = (String) Hibernate.TEXT.nullSafeGet(rs, names[0]);
- if (value == null) {
- returnnull;
- } else {
- String[] array = StringUtils.split(value.trim(), ' ');
- for (int i = 0; i < array.length; i++) {
- array[i] = WhitespaceEscapeUtil.unescape(array[i]);
- }
- return array;
- }
- }
-
- @Override
- publicvoid nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
- if (value == null) {
- Hibernate.TEXT.nullSafeSet(st, null, index);
- } else {
- String[] array = (String[]) value;
- String[] copy = new String[array.length];
- for (int i = 0; i < array.length; i++) {
- copy[i] = WhitespaceEscapeUtil.escape(array[i]);
- }
- Hibernate.TEXT.nullSafeSet(st, ' '+StringUtils.join(copy, ' ')+' ', index);
- }
- }
Now we carefully implement the org.hibernate.criterion.Criterion interface.
- publicclass GenericStringArrayContainsCriterion extends LikeExpression {
- public GenericStringArrayContainsCriterion(String propertyName, String value) {
- super(propertyName, "% "+WhitespaceEscapeUtil.escape(value) + " %")
- }
- }
Clear business that implementation through like is not very effective from the point of view of productivity. For optimization purposes, we will write the same thing using the capabilities of PostgreSQL 8.x.- publicclass PostgresStringArrayContainsCriterion implements Criterion {
-
- privatefinal String propertyName;
- privatefinal String value;
-
- privatefinal String TEMPLATE = "to_tsvector('simple', {column}) @@ plainto_tsquery('simple', ?)";
- privatestaticfinalchar TAG_SEPARATOR = ' ';
-
- public PostgresStringArrayContainsCriterion(String propertyName, String value) {
- this.propertyName = propertyName;
- this.value = WhitespaceEscapeUtil.escape(value);
- }
-
- public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
- return StringHelper.replace(TEMPLATE, "{column}", criteriaQuery.getColumn(criteria, propertyName));
- }
-
- public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
- returnnew TypedValue[]{new TypedValue(Hibernate.STRING, value, EntityMode.POJO)};
- }
- }
And using the “strategy” template, we will choose the implementation depending on the current dialect: - publicclass StringArrayContainsCriterion implements Criterion {
-
- privatefinal String propertyName;
- privatefinal String value;
-
-
- public StringArrayContainsCriterion(String propertyName, String value) {
- this.propertyName = propertyName;
- this.value = value;
- }
-
- public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
- return getStrategy(criteriaQuery.getFactory().getDialect()).toSqlString(criteria, criteriaQuery);
- }
-
- public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
- return getStrategy(criteriaQuery.getFactory().getDialect()).getTypedValues(criteria, criteriaQuery);
- }
-
- public Criterion getStrategy(Dialect dialect) {
- if (dialect instanceof PostgreSQLDialect) {
- returnnew PostgresStringArrayContainsCriterion(propertyName, value);
- } else {
- returnnew GenericStringArrayContainsCriterion(propertyName, value);
- }
- }
- }
-
Well, that's all. Now we can save and filter custom types.
______________________