# Hibernate条件查询工具类使用

Hibernate 复杂查询需要依赖工具类—— **HqlWhereHelper** ，通过调用工具类 **buildConditions()** 方法，生成带顺序的条件列表**LinkedList<Condition>**  ，最终按顺序生成HQL语句。

## 简单使用示例

**HqlWhereHelper** 调用示例：

```java
LinkedList<Condition> conditions = HqlWhereHelper.getInstance().and("key","value").buildConditions();
```

**HqlWhereHelper** 条件之间分为AND和OR，sql参数过滤方式 **FilterType** 又分为EQUAL、NOTEQUAL、LIKE、IN、NOTIN

| **FilterType** | 对应sql符号 |
| -------------- | ----------- |
| EQUAL          | =           |
| NOTEQUAL       | !=          |
| LIKE           | like        |
| IN             | in          |
| NOTIN          | not in      |
| ISNULL         | is null     |
| ISNOTNULL      | is not null |
| GT             | >           |
| LT             | <           |
| GE             | >=          |
| LE             | <=          |



**HqlWhereHelper ** 条件组合的方法列表如下，所有的方法都可以重复调用并随意组合，第一个方法也可以随意调用，不会多生成一个and或者or：

```java
 	/**
     * 获取工具类实例
     *
     * @return
     */
	public static HqlWhereHelper getInstance();

	/**
     * 通过条件列表实例化，新增条件会添加到此列表之后，适用于已有condition列表的情况下使用
     *
     * @param conditionList 条件列表
     * @return
     */
	public static HqlWhereHelper getInstance(LinkedList<Condition> conditionList);
        
    /**
     * 通过hql实例化，后续条件直接拼接到hql语句后
     *
     * @param hql
     * @return
     */
	public static HqlWhereHelper getInstance(String hql);

    /**
     * 通过hql、条件列表实例化
     *
     * @param hql           hql语句
     * @param conditionList 条件列表
     * @return
     */
	public static HqlWhereHelper getInstance(String hql,LinkedList<Condition> conditionList);
	
	/**
     * 使用and拼接map中的参数，sql参数过滤方式为filterType
     *
     * @param paramMap   参数map
     * @param filterType sql参数过滤方式
     * @return
     */
    public HqlWhereHelper andParamMap(Map<String, Object> paramMap, FilterType filterType);

    /**
     * 使用or拼接map中的参数，sql参数过滤方式为filterType
     *
     * @param paramMap   参数map
     * @param filterType sql参数过滤方式
     * @return
     */
    public HqlWhereHelper orParamMap(Map<String, Object> paramMap, FilterType filterType);

    /**
     * 使用and拼接参数，默认过滤方式为FilterType.EQUAL
     *
     * @param key   参数key
     * @param value 参数value
     * @return
     */
    public HqlWhereHelper and(String key, Object value);

    /**
     * 使用or拼接参数，默认过滤方式为FilterType.EQUAL
     *
     * @param key   参数key
     * @param value 参数value
     * @return
     */
    public HqlWhereHelper or(String key, Object value);

    /**
     * 使用and拼接参数，过滤方式为FilterType.LIKE
     *
     * @param key   参数key
     * @param value 参数value
     * @return
     */
    public HqlWhereHelper andLike(String key, Object value);

    /**
     * 使用or拼接参数，过滤方式为FilterType.LIKE
     *
     * @param key   参数key
     * @param value 参数value
     * @return
     */
    public HqlWhereHelper orLike(String key, Object value);

    /**
     * 使用and拼接参数
     *
     * @param key        参数key
     * @param value      参数value
     * @param filterType 过滤方式
     * @return
     */
    public HqlWhereHelper and(String key, Object value, FilterType filterType);

    /**
     * 使用or拼接参数
     *
     * @param key        参数key
     * @param value      参数value
     * @param filterType 过滤方式
     * @return
     */
    public HqlWhereHelper or(String key, Object value, FilterType filterType);

 	/**
     * 使用and 拼接组合条件的前括号
     *
     * @return
     */
    public HqlWhereHelper addGroup();

    /**
     * 使用or 拼接组合条件的前括号
     *
     * @return
     */
    public HqlWhereHelper orGroup();

    /**
     * 后括号
     *
     * @return
     */
    public HqlWhereHelper endGroup();

    /**
     * join一对一关联对象，生成默认别名(下划线加上类名首字母大写)
     *
     * @param field        关联对象在主表中的字段名
     * @param mappingClazz 关联对象class
     * @return
     */
	public HqlWhereHelper join(String field, Class<?> mappingClazz);
	
	/**
     * join一对多关联对象，生成默认别名(下划线加上类名首字母大写)
     *
     * @param field        关联对象在主表中的字段名
     * @param mappingClazz 关联对象class
     * @return
     */
	public HqlWhereHelper joinFetch(String field, Class<?> mappingClazz);

 	/**
     * 一对一关联对象
     *
     * @param field        关联对象在主表中的字段名
     * @param mappingClazz 关联对象class
     * @param aliasName    查询别名
     * @return
     */
    public HqlWhereHelper join(String field, Class<?> mappingClazz, String aliasName);

	/**
     * 一对多关联对象
     *
     * @param field        关联对象在主表中的字段名
     * @param mappingClazz 关联对象class
     * @param aliasName    查询别名
     * @return
     */
    public HqlWhereHelper joinFetch(String field, Class<?> mappingClazz, String aliasName);
```

组合条件示例：

```java
LinkedList<Condition> conditions = HqlWhereHelper.getInstance()
                .or("key1","value1")
                .or("key2","value2")
                .and("key3","value3")
                .andLike("key4","value4")
                .orLike("key5","value5")
                .buildConditions();
```

## 组合嵌套条件

在HQL中有部分条件需要组合和嵌套，**HqlWhereHelper** 支持使用 `addGroup()` 、`orGroup()`、`endGroup()`来实现组合和嵌套，`addGroup()`与`orGroup()`需要配合`endGroup()`来写。

addGroup 生成的代码是AND 加上左括号

```sql
AND (
```

orGroup生成的代码是 OR 加上左括号

```sql
OR (
```

而endGroup生成右括号

```sql
)
```

以下是示例：

```java
LinkedList<Condition> conditions = HqlWhereHelper.getInstance()
                .and("key1","value1")
    			.addGroup()
                .and("key2",10,FilterType.GE)
    			.and("key2",50,FilterType.LE)
    			.endGroup()
                .orLike("key3","value3")
                .buildConditions();
```

上面代码生成的条件如下：

```sql
WHERE key1=value1 AND (key2>=10 AND key2<=50) OR key3 like 'value3'
```



## 级联查询

当实体类中有相关关联，并且需要用关联对象中的某个字段来做查询条件，可以使用join（一对一），joinFetch（一对多）将关联对象映射添加进来，并直接使用关联对象别名来区分查询字段。

下面使用城市City、地区Area来举例，城市为主控方，维护着多个区域类，可以通过地区名称来过滤城市。

City类

```java
@Table(name = "ldp_city")
@Getter
@Setter
@Entity
@NoArgsConstructor
public class City implements Serializable {

    public City(String id) {
        this.id = id;
    }

    /**
    * 主键ID
    */
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "custom-uuid")
    @GenericGenerator(name = "custom-uuid", strategy = CustomUUIDGenerator.STRATEGY_UUID)
    private String id;

    /**
    * 城市名称
    */
    @Column(name = "name")
    private String name;

    /**
    * 创建者ID
    */
    @Column(name = "create_id")
    @AutoComputed(command = ComputedCommand.USERID)
    private String createId;

    /**
    * 创建时间
    */
    @Column(name = "create_time")
    @AutoComputed(command = ComputedCommand.DATETIME)
    private Date createTime;

    /**
    * 更新者ID
    */
    @Column(name = "update_id")
    @AutoComputed(command = ComputedCommand.USERID)
    private String updateId;

    /**
    * 更新时间
    */
    @Column(name = "update_time")
    @AutoComputed(command = ComputedCommand.DATETIME)
    private Date updateTime;

    /**
    * 双向，一对多关联
    */
    @JsonIgnoreProperties("city")
    @OneToMany(mappedBy = "city", fetch = FetchType.EAGER )
    private Set<LdpArea> areas= new HashSet<>();

}
```

Area类

```java
@Table(name = "ldp_area")
@Getter
@Setter
@Entity
@NoArgsConstructor
public class Area implements Serializable {

    public Area(String id) {
        this.id = id;
    }

    /**
    * 主键ID
    */
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "custom-uuid")
    @GenericGenerator(name = "custom-uuid", strategy = CustomUUIDGenerator.STRATEGY_UUID)
    private String id;

    /**
    * 地区名称
    */
    @Column(name = "name")
    private String name;

    /**
    * 创建者ID
    */
    @Column(name = "create_id")
    @AutoComputed(command = ComputedCommand.USERID)
    private String createId;

    /**
    * 创建时间
    */
    @Column(name = "create_time")
    @AutoComputed(command = ComputedCommand.DATETIME)
    private Date createTime;

    /**
    * 更新者ID
    */
    @Column(name = "update_id")
    @AutoComputed(command = ComputedCommand.USERID)
    private String updateId;

    /**
    * 更新时间
    */
    @Column(name = "update_time")
    @AutoComputed(command = ComputedCommand.DATETIME)
    private Date updateTime;

    /**
    * 双向，多对一关联
    */
    @JsonIgnoreProperties("areas")
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "c_id")
    private City city;
}
```

通过城市的name进行查询，构造查询ConditionList

```java
HqlWhereHelper conditions = HqlWhereHelper.getInstance()
    .and("name", "上海")
    .buildConditions();
```

通过地区名称的name进行查询，构造查询ConditionList，没有传别名，默认使用下划线+类名首字母小写(_area)

```java
HqlWhereHelper conditions = HqlWhereHelper.getInstance()
                .joinFetch("areas", Area.class)
                .and("_area.name", "浦东新区");
```

也可以自定义的别名，通过别名进行查询

```java
HqlWhereHelper conditions = HqlWhereHelper.getInstance()
                .joinFetch("areas", Area.class, "a")
                .and("a.name", "浦东新区");
```

#### 多级级联的样例

员工实体中有组织关联属性org，组织实体中有职位关联属性positions，下面样例则是通过职位过滤员工信息

```java
// 不指定class 
LinkedList<Condition> conditions = HqlWhereHelper.getInstance()
                .join("org", "org")
                .join("org.positions", "post")
                .and("post.id", "bd5b28b7ccd74ba28708c95db54230f0")
                .buildConditions();

List list = genericDaoService.findByConditions(LdpMcsEmployeeInfo.class, conditions);
```

另外一种写法需要指定class，这两种写法查询结果一致

```java
// 指定class
LinkedList<Condition> conditions = HqlWhereHelper.getInstance()
    .join("org", LdpMcsOrganization.class,"org")
    .join("org.positions", LdpMcsPosition.class,"position")
    .and("position.id", "bd5b28b7ccd74ba28708c95db54230f0")
    .buildConditions();

List list = genericDaoService.findByConditions(LdpMcsEmployeeInfo.class, conditions);
```







