1

我正在尝试创建一个 JPA 谓词以用作我的 JPA 存储库中的参数,以便根据连接表中的字段返回结果。它实际上从不过滤任何东西。我得到了主表的所有对象。JPA 标准似乎是适合这项工作的工具,因为实际应用的应用程序有许多不同的条件,并且是一个动态查询。

代码:

@Getter
@Setter
@Entity
@Table(name = "FOO")
public class Foo {
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    private String name;

    @OneToMany(mappedBy = "foo")
    private Set<Bar> bars;
}

@Getter
@Setter
@Entity
@Table(name = "BAR")
public class Bar {
    @Id
    @Column(name="id")
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    private int id;

    private String name;

    @ManyToOne
    @JoinColumn(name = "foo_id", nullable = false)
    private Foo foo;
}


public class FooSpecs {
    public Specification<Foo> barName(String name) {
        return (root, query, builder) -> {
            Root<Foo> foo = query.distinct(true).from(Foo.class);
            Join<Foo, Bar> bar = foo.join("bars", JoinType.LEFT);

            Predicate pred = builder.equal(bar.get("name"), name);

            return pred;
        };
    }
}

public interface FooRepository extends JpaRepository<Foo, Integer>, JpaSpecificationExecutor {
}

测试

@RunWith(SpringRunner.class)
@DataJpaTest
@SpringBootTest
public class JpaDemoApplicationTests {

    @Autowired
    FooRepository repo;

    @Test
    public void contextLoads() {
        FooSpecs specs = new FooSpecs();
        Specification<Foo> spec = specs.barName("test 2");
        List<Foo> foos =  repo.findAll(spec);
        // List<Foo> foos =  repo.findAll();

        assertThat(foos)
                .isNotEmpty()
                .hasSize(1);
    }
}

数据

insert into Foo(id, name) values (1, 'foo 1');
insert into Foo(id, name) values (2, 'foo 2');
insert into Foo(id, name) values (3, 'foo 3');

insert into Bar (id, name, foo_id) values (1, 'test 1', 2);
insert into Bar (id, name, foo_id) values (2, 'test 2', 1);

休眠查询输出:

Hibernate: select distinct foo0_.id as id1_1_, foo0_.name as name2_1_ from foo foo0_ cross join foo foo1_ left outer join bar bars2_ on foo1_.id=bars2_.foo_id where bars2_.name=?

我不是最熟悉连接的人,但交叉连接似乎不合适,根据我的理解,这可能是问题的一部分。

测试输出:

Expected size:<1> but was:<3> in:
<[com.example.jpademo.dto.Foo@6e0e5dec,
    com.example.jpademo.dto.Foo@56476c16,
    com.example.jpademo.dto.Foo@497b560e]>, mergedContextConfiguration = [MergedContextConfiguration@525f1e4e testClass = JpaDemoApplicationTests, locations = '{}', classes = '{class com.example.jpademo.JpaDemoApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@75f9eccc key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, 
java.lang.AssertionError: 
Expected size:<1> but was:<3> in:
<[com.example.jpademo.dto.Foo@6e0e5dec,
    com.example.jpademo.dto.Foo@56476c16,
    com.example.jpademo.dto.Foo@497b560e]>

我期望的结果是名为 'foo 1' 的 Foo

4

1 回答 1

0
public class FooSpecs {
    public Specification<Foo> barName(String name) {
        return (root, query, builder) -> {
            Join<Foo, Bar> bar = root.join("bars");
            Predicate pred = builder.equal(bar.get("name"), name);
            return pred;
        };
    }
}
于 2017-12-01T19:03:45.753 回答