简体   繁体   中英

How to use Hibernate eqOrIsNull()

I have two rows in MySQL like this

+---------+---------+
| foo     | bar     |
+---------+---------+
|         | NULL    |
|         |         |
+---------+---------+

Where empty are empty strings "" .

Now I want to get both of them. I use Criteria and Restrictions.eqOrIsNull() on both columns, but it always returns only one row.

The code is like this

criteria.add(Restrictions.eqOrIsNull("foo", ""));
        .add(Restrictions.eqOrIsNull("bar", ""));

And when I add criteria only on foo , it returns two rows. But for bar , it only returns the second, which is empty.

The javadoc says, Apply an "equal" constraint to the named property. If the value is null, instead apply "is null". Apply an "equal" constraint to the named property. If the value is null, instead apply "is null". So am I getting this wrong, or it should be used in other ways?

UPDATE :
Sorry, I'm so careless. The doc states it clearly. This method works according to the value passed to it, not the actual value of the named property stored in DB.
Source code on Github :

public static Criterion eqOrIsNull(String propertyName, Object value) {
    return value == null
            ? isNull( propertyName )
            : eq( propertyName, value );
}

So in my case, eqOrIsNull returns eq("") . I should have used disjunction of eq and isNull , like Gregory answered .

Apply an "equal" constraint to the named property. If the value is null, instead apply "is null".

This means, is null will be applied only if NULL is passed as the value. If you specify any other string as value, only equal will be applied for that.

This is useful when you're not sure about the actual value being passed at runtime as argument to the parameter value. In such a scenario, in a traditional way, either you need to put a not null check & write criteria based on the not null condition or you need to write criteria in the way mentioned by Gregory's answer.

Keeping all these facts in mind, you should get answer of your question. You're getting only those rows which contain empty value & not the one having NULL value, because you have specified an empty string as 2nd arguement. If you specify NULL as the 2nd arguement, you'll get only those rows having NULL value.

Let me know if that's helpful to you.

Check if this code does what you want -

criteria.add(Restrictions.or(Restrictions.eq("foo", ""), Restrictions.isNull("foo")))
                .add(Restrictions.or(Restrictions.eq("bar", ""), Restrictions.isNull("bar")));

This snippet uses Hibernate 3.5.0-CR-2 API.

Yeah this is very ambiguous if never used before and from a ORM abstraction perspective completely senseless to differentiate between eq null or is null. Thats legacy SQL thinking.

I first also thought it is a shortcut for or(eq("foo"), isNull("foo")) cause i have my own filter layer on top on criteria where eq always works like eqOrIsNull .

strong text

/**
 * Checks if the given property is <code>null</code> or equals the given
 * value. If the given value is <code>null</code> it is only checked for
 * being <code>null</code>.
 *
 * @param property Property name
 * @param value Value to check against
 *
 * @return Disjunction
 */
public static Criterion isValueEqOrNull(final String property, final Object value)
{
    Objects.requireNonNull(property, "property must not be null");

    if (value == null)
        return Restrictions.isNull(property);
    else
        return Restrictions.or(Restrictions.eq(property, value), Restrictions.isNull(property));
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM