Hibernate 查询存储在单独集合中的@Embeddeble对象
我有一个简单的关系,其中一个实体有许多特定于它的地址,定义为:Hibernate 查询存储在单独集合中的@Embeddeble对象,hibernate,jpa,spring-data-jpa,spring-data,Hibernate,Jpa,Spring Data Jpa,Spring Data,我有一个简单的关系,其中一个实体有许多特定于它的地址,定义为: @Entity public class Corporation { @Id private Long id; @ElementCollection @CollectionTable(name = "addresses_table", joinColumns = @JoinColumn(name = "corporation_id")) private List<Address>
@Entity
public class Corporation {
@Id
private Long id;
@ElementCollection
@CollectionTable(name = "addresses_table", joinColumns = @JoinColumn(name = "corporation_id"))
private List<Address> addresses = new ArrayList<>();
}
@实体
公营公司{
@身份证
私人长id;
@元素集合
@CollectionTable(name=“addresses\u table”,joinColumns=@JoinColumn(name=“corporation\u id”))
私有列表地址=新的ArrayList();
}
地址
类用@embeddeble
注释。这非常有效,因为公司的每次更新都会删除其所有地址,然后插入新地址。这正是我想要的行为。我尝试过的其他选项(OneToMany
,ManyToMany
)导致性能较差,因为我需要跳转,仍然无法获得简单的全部删除+全部插入行为
然而,有一个简单的要求,我需要能够查询一些标准的地址。基本上,这归结为一个简单的findAll(Pageable-Pageable,Specification spec)
方法。这对于当前和未来的用例来说已经足够了
现在的问题是,可嵌入对象不是实体,因此我无法为它们创建Spring数据存储库。我能想到的唯一选择是:
规范
。如果没有,我仍然可以接受,因为搜索地址的字段不会改变从Corporation c join c.addresses中选择sth,然后根据地址属性限制结果。在这里,我再次不确定这是否有效,是否与直接对addresses表进行简单排队一样有效
如有任何建议,将不胜感激,无论是在所描述的选项上还是在某些其他选项上。单个表都可以映射到不同的类。因此,为什么不创建另一个
地址
类,它是一个常用的@实体
类,以便您可以为它创建一个存储库,并使用您想要使用的规范
@embeddeble
地址
可被视为公司
的一个内部类,用于提供“全部删除+全部插入”行为。如果您希望域客户端只处理一个地址
类,您可以简单地在@可嵌入
地址和@实体
地址之间进行转换
代码方面,它看起来像:
@Entity
public class Corporation {
@Id
private Long id;
@ElementCollection
@CollectionTable(name = "addresses_table", joinColumns = @JoinColumn(name = "corporation_id"))
private List<CorporationAddress> addresses = new ArrayList<>();
public void addAddress(Address address){
addresses.add(new CorporationAddress(address));
}
public List<Address> getAddresses(){
return addresses.stream()
.map(CorporationAddress::toAddress).collect(toList());
}
}
//Or you can put it as the internal static nested class inside Corporation if you like
@Embeddable
public class CorporationAddress {
//Create from Address
public CorporationAddress(Address){
}
//Convert to Address
public Address toAddress(){
}
}
@Entity
public class Address {
}
@实体
公营公司{
@身份证
私人长id;
@元素集合
@CollectionTable(name=“addresses\u table”,joinColumns=@JoinColumn(name=“corporation\u id”))
私有列表地址=新的ArrayList();
公共无效地址(地址){
地址。添加(新公司地址(地址));
}
公共列表getAddresses(){
返回地址。stream()
.map(CorporationAddress::toAddress).collect(toList());
}
}
//如果愿意,也可以将其作为公司内部的内部静态嵌套类
@可嵌入
公共类公司地址{
//从地址创建
公共公司地址(地址){
}
//转换为地址
公共广播地址{
}
}
@实体
公共课堂演讲{
}
如果在您的项目中使用本机查询是可以接受的,在我看来,这将是最简单、最高效的方法:
公共接口CorporationRepo扩展了JpaRepository{
@查询(value=“选择a.city作为城市,a.street作为地址表a中的街道,其中a.corporation\u id=?1”,nativeQuery=true)
如下所示:
公共接口地址投影{
字符串getCity();
字符串getStreet();
默认地址到地址(){
返回新地址(getCity(),getStreet());
}
}
(请注意,必须在带有投影的select查询中使用别名(即a.city as city
)
然后您将能够使用地址:
corporationRepo.getAddressesByCorpId(corpId)
.stream()
.map(AddressProjection::toAddress)
.forEach(System.out::println);
如果您不能使用本机查询(我不知道为什么),您可以使用第二个选项-带有join的查询:
公共接口CorporationRepo扩展了JpaRepo{
@查询(value=“选择a.city作为城市,a.street作为地址表a中的街道,其中a.corporation\u id=?1”,nativeQuery=true)
列出getAddressesByCorpId(长corpId);
@查询(“从公司c中选择a加入c地址a,其中c.id=?1”)
列表readAddressesByCorpId(长corpId);
}
corporationRepo.readAddressesByCorpId(corpId.forEach)(System.out::println);
它将生成这样一个查询:
选择
a、 作为col0的城市,
a、 街如可乐
从…起
c公司
c.id=a.corporation\u id上的表a的内部联接地址
哪里
c、 id=1
当然,它不像第一个那样是最优的,但也不是完全糟糕的,因为它只有一个索引字段的“连接”
您的第一个选项与第二个选项相同,因为根据规范,您将得到相同的“加入”查询