Java Spring 具有@OneToMany 关系的数据@Query returns 无结果
Java Spring Data @Query with @OneToMany relation returns no result
我有以下实体:
@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;
...
以及以下存储库界面class:
@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);
}
现在,我正在尝试 运行 以下集成测试,但它失败了,我完全不知道为什么。不幸的是,我是 Spring 的初学者,我正在努力学习它 ;-)
@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>
为什么结果是空的。我的测试设置错了吗?实体关系?
没关系,如果你能帮助我。
您在 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));
}
您可以使用这样的查询方法。使用下划线(_)得到属性child.
@Repository
public interface CustomerRepository extends JpaRepository<Customer, Long> {
List<Customer> findByAddresses_City(String city);
}
我有以下实体:
@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;
...
以及以下存储库界面class:
@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);
}
现在,我正在尝试 运行 以下集成测试,但它失败了,我完全不知道为什么。不幸的是,我是 Spring 的初学者,我正在努力学习它 ;-)
@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>
为什么结果是空的。我的测试设置错了吗?实体关系? 没关系,如果你能帮助我。
您在 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));
}
您可以使用这样的查询方法。使用下划线(_)得到属性child.
@Repository
public interface CustomerRepository extends JpaRepository<Customer, Long> {
List<Customer> findByAddresses_City(String city);
}