2015-06-04 38 views
2

我有以下实体:Java的春季数据@Query与@OneToMany关系不返回结果

@Entity 
public class Customer extends BaseEntity { 

    private String firstname; 
    private String lastname; 
    @OneToMany(mappedBy = "customer", cascade = CascadeType.ALL) 
    private Set<Address> addresses; 

    ... 

@Entity 
public class Address extends BaseEntity { 

    private String street; 
    private String houseNumber; 
    private String zipCode; 
    private String city; 
    @ManyToOne 
    private Customer customer; 

    ... 

而下面的库接口类:

@Repository 
public interface CustomerRepository extends CrudRepository<Customer, Long> { 

    @Query("select c from Customer c join c.addresses a where (a.city = :cityName)") 
    List<Customer> findByCity(@Param("cityName")String city); 

} 

现在,我试图运行以下集成测试,但它失败了,我绝对不知道为什么。不幸的是,我和春天有个初学者,我试图了解它;-)

@Test 
public void testFindCustomerByCity() { 
    Customer customer = new Customer("Max", "Tester"); 
    Address address = new Address("Street", "1", "12345", "City"); 
    HashSet<Address> addresses = new HashSet<Address>(); 
    addresses.add(address); 
    customer.setAddresses(addresses); 
    Customer savedCustomer = customerRepository.save(customer); 
    Assert.assertTrue(savedCustomer.getId() > 0); 

    List<Customer> customerList = customerRepository.findByCity("City"); 
    Assert.assertThat(customerList.size(), is(1)); 
} 

的错误信息是:

java.lang.AssertionError: Expected: is <1> but: was <0>

为什么结果是空的。我的测试设置是否错误?实体关系? 如果你能帮助我,那会很好。

+2

您尚未将地址上的客户设置为客户的地址。 –

+0

@M好,我接着说:address.setCustomer(客户);'和它的作品...但我真诚不明白它...我想,这是足以让父实体孩子的实体。也许你可以很快解释它,或给我一个链接网址作为提示...无论如何,感谢你的快速答案。 – Adrian

+0

您有一个'null'客户的地址,您指定关系由客户地址管理。如果没有设置数据库应该如何知道存在关系。同样,执行'setAddresses'是向客户添加地址的一种非常糟糕的方式。删除该方法并创建一个'addAddress'方法,您可能在其中管理关系。 –

回答

4

您在Customer实体的addresses字段中有@OneToMany(mappedBy = "customer", cascade = CascadeType.ALL)。这基本上意味着该关系由Address实体中的customer字段中的值管理。

在你的测试代码,你只设置对客户的地址,但没有对地址的客户。它仍然是空的,所以可能在数据库中有2条记录,但没有关系。因此,查询中不会返回任何内容。

像设置setAddresses一样设置集合是在JPA环境中处理事务的一种非常糟糕的方法(当您在已存在的实例上执行此操作时将覆盖持久集合)。取消setAddresses方法并改为在Customer上创建addAddress方法。

@Entity 
public class Customer extends BaseEntity { 

    private String firstname; 
    private String lastname; 

    @OneToMany(mappedBy = "customer", cascade = CascadeType.ALL) 
    private final Set<Address> addresses = new HashSet<Address>(); 

    // No setter, only a getter which returns an immutable collection 
    public Set<Address> getAddresses() { 
     return Collections.unmodifiableSet(this.addresses); 
    } 

    public void addAddress(Address address) { 
     address.setCustomer(this); 
     this.addresses.add(address); 
    } 

} 

这也清理了你的测试代码。

@Test 
public void testFindCustomerByCity() { 
    Customer customer = new Customer("Max", "Tester"); 
    customer.addAddress(new Address("Street", "1", "12345", "City")); 
    Customer savedCustomer = customerRepository.save(customer); 

    Assert.assertTrue(savedCustomer.getId() > 0); 

    List<Customer> customerList = customerRepository.findByCity("City"); 
    Assert.assertThat(customerList.size(), is(1)); 
} 
0

您可以使用像这样的查询方法。使用下划线(_)来获得财产子女。

@Repository 
public interface CustomerRepository extends JpaRepository<Customer, Long> { 
    List<Customer> findByAddresses_City(String city); 
} 
+0

下划线不应该是必需的。 – CorayThan