Java JPA/Hibernate:表中有多个不必要的实体

Java JPA/Hibernate:表中有多个不必要的实体,java,hibernate,jpa,mapping,database-normalization,Java,Hibernate,Jpa,Mapping,Database Normalization,我是新来的,在JPA也是新来的!我用以下实体开发了一个小型JPA应用程序: 客户(姓名、姓名、ID)有地址(邮政编码、城市、ID)。这些实体之间的关系是一对一(客户的观点)和一对一(地址的观点) 代码(部分)如下:(不带getter/setter) @实体 公共类AddressEntity实现可序列化{ 私有静态最终长serialVersionUID=1L; @身份证 @GeneratedValue(策略=GenerationType.AUTO) 私有int-id; 私人城市; 私有int-zi

我是新来的,在JPA也是新来的!我用以下实体开发了一个小型JPA应用程序:

客户(姓名、姓名、ID)有地址(邮政编码、城市、ID)。这些实体之间的关系是一对一(客户的观点)和一对一(地址的观点)

代码(部分)如下:(不带getter/setter)

@实体
公共类AddressEntity实现可序列化{
私有静态最终长serialVersionUID=1L;
@身份证
@GeneratedValue(策略=GenerationType.AUTO)
私有int-id;
私人城市;
私有int-zipCode;
@纵队
@ElementCollection(targetClass=CustomerEntity.class)
私人名单客户;
公共地址实体(){}
@OneToMany(级联=级联类型.ALL,
fetch=FetchType.EAGER,
mappedBy=“addressentity”)
公共列表getCustomers(){
返回客户;
}
@实体
公共类CustomerEntity实现可序列化{
私有静态最终长serialVersionUID=1L;
@身份证
@GeneratedValue(策略=GenerationType.AUTO)
私钥;
私有字符串preName,姓氏;
@多通(targetEntity=AddressEntity.class,cascade=CascadeType.ALL)
@JoinColumn(name=“Address\u ID”)
私人地址实体地址;
公共CustomerEntity(){}
}

现在我想添加两个人: 1) 巴特·辛普森1234斯普林菲尔德 2) 荷马·辛普森1234斯普林菲尔德

问题是,在地址表中,Springfield出现了两次。但这不是规范化数据库的意义!我怎么知道AddressEntity只有在以前不存在的情况下才被添加

谢谢你的回答,
eniac保留新地址

可能有许多
地址实体
具有相同的
城市
Zipcode
。如果您要求给定的
客户属性
与相同的
地址
相关,那么您必须使用该特定实体。因此,也可以使用用于Bart for Homer的相同的
地址实体

CustomerEntity bart = new CustomerEntity();
//Set Barts’s fields.
CustomerEntity homer = new CustomerEntity();
//Set Homers’s fields.


AddressEntity simpsonsPlace = new AddressEntity();
//set 1234 and Springfield.

bart.setAdress(simpsonsPlace);
homer.setAdress(simpsonsPlace);

List<CustomerEntity> simpsons = new ArrayList<CustomerEntity>();
simpsons.add(bart);
simpsons.add(homer);
simpsonsPlace.setCustomers(simpsons);

yourEntityManager.persist(bart);
yourEntityManager.persist(homer);   
例如,更好的方法可能是形成Zip/HouseNumber的复合PK。这可以确保数据库中已经存在Zip/HouseNumber组合的任何
AddressEntity
都将被视为分离的对象,并且当然在数据库中只出现一次

嵌入

您的
@ElementCollection
@OneToMany
都是针对您的CustomerEntity实体的

根据JPA规范11.1.14

ElementCollection注释定义的实例集合 基本类型或可嵌入类

因此,以
@ElementCollection
为目标的实体是不正确的

您需要两个实体之间的关系,因此,在您的
AddressEntity
中,您只需要使用
@OneToMany
并删除
@ElementCollection
。您还需要将(使用
mappedBy
)映射到目标类的字段,而不是目标类本身

@Entity
public class AddressEntity implements Serializable{
private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;

private String city;    
private int zipCode;


@OneToMany(cascade=CascadeType.ALL,
        fetch=FetchType.EAGER,
        mappedBy="address") //Not addressentity
private List<CustomerEntity> customers;


public AddressEntity() {}

public List<CustomerEntity> getCustomers() {
    return customers;
}
@实体
公共类AddressEntity实现可序列化{
私有静态最终长serialVersionUID=1L;
@身份证
@GeneratedValue(策略=GenerationType.AUTO)
私有int-id;
私人城市;
私有int-zipCode;
@OneToMany(级联=级联类型.ALL,
fetch=FetchType.EAGER,
mappedBy=“address”)//不是addressentity
私人名单客户;
公共地址实体(){}
公共列表getCustomers(){
返回客户;
}

或者,您可以将CustomerEntity定义为一个
@embedded
,而不是一个
@entity
。通过这种方式,您可以使用
@ElementCollection
AddressEntity
定位
CustomerEntity
,但
CustomerEntity
本身不是一个实体,无法独立处理因为它依赖于
AddressEntity

,所以可能有更好的方法,但是首先尝试持久化地址,然后将其添加到2个用户并持久化这些用户。为了做到这一点,您必须删除或更改
级联类型。
自定义属性中的所有
CascadeType.REFRESH
可能可以)。无论如何,使用ALL似乎有点奇怪,主要是因为在您当前的代码中,删除一个客户将删除可能分配给另一个用户的地址。谢谢您的建议!但是您描述的方式与以前的效果相同。其中一些问题取决于您处理的实体的附加性,您可以添加摘录吗保留这些实体的代码是什么?谢谢你的回答。删除@ElementCollection并选择注释方式并不能解决问题problem@Eniac-请参阅更新,您的地址实体是不同的实体,将保留两次,您需要确保在fac中将客户与相同的地址实体关联不打算用作同一地址。
CustomerEntity homer = new CustomerEntity();
homer.setAdress(detachedAddress);
yourEntityManager.merge(homer);
@Entity
public class AddressEntity implements Serializable{
private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;

private String city;    
private int zipCode;


@OneToMany(cascade=CascadeType.ALL,
        fetch=FetchType.EAGER,
        mappedBy="address") //Not addressentity
private List<CustomerEntity> customers;


public AddressEntity() {}

public List<CustomerEntity> getCustomers() {
    return customers;
}