【问题标题】:Specifications and (null) Many-To-One Relationship规范和(空)多对一关系
【发布时间】:2014-10-06 10:17:03
【问题描述】:

我有一个 MVC 控制器,它以 JSON 形式返回联系人列表。在前端,我使用 jquery 数据表插件。前端有一个搜索栏来过滤实体列表。

我的实体:

@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));

needle 是来自前端的搜索键,并带有周围的 % 掩码(例如“%asdf%”)

我的问题是,如果联系人没有公司,则说明无法按预期工作。

例如我有 3 个联系人:

  1. 姓:Schmitz,名字:Max,公司:(null)
  2. 姓:Schmitz,名字:Moritz,公司:XY
  3. 姓:Muster,名字:Max,公司:XY

    • 如果我现在输入 Schmitz 作为搜索键,则只返回联系人 2,不返回联系人 1。
    • 如果我输入 max 作为搜索键,则只返回联系人 3,不返回联系人 1
    • 仅当搜索键为 null/空时,才会返回所有联系人

我错过了什么?

亲切的问候 里齐

【问题讨论】:

    标签: spring-data-jpa specifications many-to-one


    【解决方案1】:

    回答我自己;)

    在研究了 sql 查询后,我找到了解决方案。我必须重写我的规范。在相关实体上,我必须添加左连接路径以防止标准构建器自动使用交叉/内连接。

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

    所以...

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

    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);
            }
        };
    }
    

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

    亲切的问候里齐

    【讨论】:

      猜你喜欢
      • 2017-08-19
      • 2013-04-10
      • 2013-04-19
      • 2015-06-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-09
      相关资源
      最近更新 更多