无法使@Formula属性与CriteriaBuilder

时间:2017-09-21 09:38:28

标签: java jpa spring-data spring-data-jpa

我有一个类似以下的实体,我使用@Formula从其他表中填充clientId

@Entity
public class Failure {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public int id;
    public String name;
    @ManyToOne(cascade = {CascadeType.MERGE, CascadeType.REFRESH} )
    public PVPlant pvPlant;

    @Formula("(SELECT cl.id from failure f " +
            "INNER JOIN pvplant p ON f.pv_plant_id = p.id " +
            "INNER JOIN company co ON p.company_id = co.id "+
            "INNER JOIN client cl ON co.client_id = cl.id "+
            "WHERE f.id = id) ")
    public Integer clientId;
}

虽然CrudRepository<Failure,Integer> JPA方法getByClientId工作正常但我正在尝试使用MapSpecification CriteriaBuilder的{​​{1}}密钥进行过滤。 }。

public MySpecifications {

    public static Specification<Failure> equalToEachColumn(HashMap<String,Object> map) {

        return new Specification<Failure>() {
            @Override
            public Predicate toPredicate(Root<Failure> root, CriteriaQuery<?> cq, CriteriaBuilder builder) {

                return builder.and(root.getModel().getAttributes().stream().map(a ->
                        {
                            if (map.containsKey(a.getName())) {
                                    Object val = map.get(a.getName());
                                    return builder.equal(root.<Integer>get(a.getName()), Integer.parseInt(val.toString()));
                            }
                            return builder.disjunction();
                        }
                    ).toArray(Predicate[]::new)
                );
            }
        };
    }

 }

当我在id中传递HashMap时,它工作正常,但当我clientId时,它不会发回任何内容。有趣的是getAttributes()实际上返回clientId但似乎builder.equal(root.<Integer>get(a.getName()), Integer.parseInt(val.toString()))是假的而不是真的

这就是我使用规范的方式:

failureRepository.findAll(Specifications.where(MySpecifications.equalToEachColumn(map)));

我错过了什么吗?

提前致谢!

2 个答案:

答案 0 :(得分:1)

我不希望这会起作用,但是你可以通过使用数据库视图作为@Formula的替代方法并使用@SecondaryTable在表和视图中映射实体来使其工作。

//failures_client_vw is a 2 column db view: failure_id, client_id
@Table(name = "failures")
@SecondaryTable(name = "failures_client_vw",  
       pkJoinColumns = @PrimaryKeyJoinColumn(name = "failure_id"))
@Entity
public class Failure {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public int id;

    public String name;

    @ManyToOne(cascade = {CascadeType.MERGE, CascadeType.REFRESH} )
    public PVPlant pvPlant;

    @Column(name = "client_id", table = "failures_client_vw")
    public Integer clientId;
}

然后,您可以像查询任何其他属性一样查询clientId。

https://en.wikibooks.org/wiki/Java_Persistence/Tables#Multiple_tables

答案 1 :(得分:0)

实际问题是我正在使用

builder.disjunction()

and()中创建0 = 1个错误谓词的

当我用

替换它时

builder.conjunction()(创建1 = 1个真实谓词)

在我的代码中它工作正常。因此,@Formula属性的行为与表格中的属性相同,似乎不需要SecondaryTable和新的View。显然在我之前的测试中,我使用的是一个在类中只有id的实体,当我添加clientId时,它误导我相信@Formula属性不起作用,而它是分离的来自破坏clientId的id