JPA / Hibernate:表中多个不必要的entires

时间:2015-08-14 08:15:00

标签: java hibernate jpa mapping database-normalization

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

客户(姓名,名称,ID)有一个地址(ZIP_Code,city,ID)。这些实体之间的关系是ManyToOne(Customer's perpective)和OneToMany(Address'透视图)。

代码(部分)如下:(没有getter / setters)

@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;


@Column
@ElementCollection(targetClass=CustomerEntity.class)
private List<CustomerEntity> customers;


public AddressEntity() {}


@OneToMany(cascade=CascadeType.ALL,
        fetch=FetchType.EAGER,
        mappedBy="addressentity")
public List<CustomerEntity> getCustomers() {
    return customers;
}



@Entity
public class CustomerEntity implements Serializable {

    private static final long serialVersionUID = 1L;

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

private String preName, surName;

@ManyToOne(targetEntity=AddressEntity.class, cascade=CascadeType.ALL)
@JoinColumn(name="Address_ID")
private AddressEntity address;

public CustomerEntity() {}

}

现在我要添加两个人: 1)Bart Simpson 1234 Springfield 2)Homer Simpson 1234 Springfield

问题是在地址表中Springfield出现两次。但这不是规范化数据库的意义!我怎么才能意识到AddressEntity只在以前不存在时添加!

感谢您的回答, ENIAC

1 个答案:

答案 0 :(得分:0)

保留新地址

可能有许多AddressEntities具有相同的CityZipcode。如果您要求给定CustomerEntity与同一address相关,则必须使用该特定实体。因此,使用与荷兰巴特一样的AddressEntity

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);   

与现有地址相关联。

如果您在bart之后的某个时间创建本垒打,那么您需要将bart与现有的address相关联。也许你会从客户端传入address。这将填充id字段,并且将是分离的实体。您可以将此实体与em.merge()操作一起使用;

CustomerEntity homer = new CustomerEntity();
homer.setAdress(detachedAddress);
yourEntityManager.merge(homer);

更好的方法可能是形成Zip / HouseNumber的复合PK。这样可以确保DB中已有的任何带有Zip / HouseNumber组合的AddressEntity将被视为分离对象,当然只会在数据库中出现一次。

<强> Embeddables

您同时将@ElementCollection@OneToMany定位到您的CustomerEntity 实体

根据JPA Spec 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;
}

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