2014-10-06 73 views
4

我有一个MVC控制器,返回一个联系人列表为JSON。在前端我使用jQuery数据表插件。前端有一个搜索栏来过滤实体列表。规范和(null)多对一关系

我的实体:

@Entity 
public class Contact implements Serializable { 

    protected final static Logger LOGGER    = LoggerFactory.getLogger(Contact.class); 

    private static final long  serialVersionUID = -3691953100225344828L; 

    @Id 
    @GeneratedValue(generator = "hibernate-uuid") 
    @Column(length = 36, unique = true) 
    private String     id; 

    @Version 
    @JsonIgnore 
    private int      version; 

    private String     firstname; 
    private String     lastname; 

    @ManyToOne 
    private Company     company; 

    ... GETTER/SETTER ... 
} 

@Entity 
public class Company implements Serializable { 

    protected final static Logger LOGGER    = LoggerFactory.getLogger(Company.class); 

    private static final long  serialVersionUID = -7863930456400256944L; 

    @Id 
    @GeneratedValue(generator = "hibernate-uuid") 
    @Column(length = 36, unique = true) 
    private String     id; 

    private String     companyName; 
    private String     companyName1; 
    private String     companyName2; 

    ... GETTER/SETTER ... 
} 

我使用服务器端处理的搜索领域,在服务器端我使用的规格。

public class ContactSpecifications { 

    public static Specification<Contact> contactFirstnameLike(final String needle) { 
     return new Specification<Contact>() { 

      @Override 
      public Predicate toPredicate(Root<Contact> root, CriteriaQuery<?> query, CriteriaBuilder cb) { 
       return cb.like(cb.lower(root.<String> get(Contact_.firstname)), needle != null ? needle.toLowerCase() : null); 
      } 
     }; 
    } 

    public static Specification<Contact> contactLastnameLike(final String needle) { 
     return new Specification<Contact>() { 

      @Override 
      public Predicate toPredicate(Root<Contact> root, CriteriaQuery<?> query, CriteriaBuilder cb) { 
       return cb.like(cb.lower(root.<String> get(Contact_.lastname)), needle != null ? needle.toLowerCase() : null); 
      } 
     }; 
    } 

    public static Specification<Contact> contactFullnameLike(final String needle) { 
     return new Specification<Contact>() { 

      @Override 
      public Predicate toPredicate(Root<Contact> root, CriteriaQuery<?> query, CriteriaBuilder cb) { 
       return cb.or(cb.like(cb.lower(root.<String> get(Contact_.lastname)), needle != null ? needle.toLowerCase() : null), cb.like(cb.lower(root.<String> get(Contact_.firstname)), needle != null ? needle.toLowerCase() : null)); 
      } 
     }; 
    } 

    public static Specification<Contact> contactCompanyCompanyNameLike(final String needle) { 
     return new Specification<Contact>() { 

      @Override 
      public Predicate toPredicate(Root<Contact> root, CriteriaQuery<?> query, CriteriaBuilder cb) { 
       final Path<Company> company = root.<Company> get(Contact_.company); 
       return cb.like(cb.lower(company.<String> get(Company_.companyName)), needle != null ? needle.toLowerCase() : null); 
      } 
     }; 
    } 
} 

我的数据库查询

contactRepository.findAll(specifications, new PageRequest(0,100)); 

和规格

specifications = Specifications.where(ContactSpecifications.contactFullnameLike(needle)).or(ContactSpecifications.contactCompanyCompanyNameLike(needle)); 

针是从前端的搜索关键字,并与周边%掩盖(例如 “%ASDF%”)

我的问题是,如果联系人没有公司,规格不按预期工作。

例如我有3个联系人:

  1. 姓氏:施米茨,名字:最大,公司:(空)
  2. 姓氏:施米茨,姓:Moritz的公司:XY
  3. 姓氏: Muster,Firstname:Max,公司:XY

    • 如果我现在输入Schmitz作为搜索键,只有联系人2返回,联系人1不是。
    • 如果我输入的最大搜索键,只有接触3回,接触1不
    • 只有当搜索键是空/空,所有联系人返回

我错过了什么?

亲切的问候 Rizzi的

回答

2

答案我自己;)

研究后,SQL查询我找到了解决办法。我必须重写我的规格。在相关实体上,我必须添加左连接路径以防止条件生成器自动使用交叉/内连接。

内部连接只返回实体,它具有所有字段设置。如果某个实体关系为空,则此实体将从结果列表中删除。正常的内部连接行为。

so ...

正确的规格必须是这样的。

public static Specification<Contact> contactCompanyCompanyNameLike(final String needle) { 
    return new Specification<Contact>() { 

     @Override 
     public Predicate toPredicate(Root<Contact> root, CriteriaQuery<?> query, CriteriaBuilder cb) { 
      final Join<Contact,Company> company = root.join(Contact_.company, JoinType.LEFT); 
      return cb.like(cb.lower(company.<String> get(Company_.companyName)), needle != null ? needle.toLowerCase() : null); 
     } 
    }; 
} 

通过这个小的修改,它现在开始正常工作。

亲切的问候Rizzi