这就是我想要做的...我有一个人
@Entity
@Table(name = "PERSON",
uniqueConstraints = {
@UniqueConstraint(columnNames = {"SSN"})
}
)
@DynamicInsert(true)
@DynamicUpdate(true)
@SelectBeforeUpdate(true)
public class Person implements java.io.Serializable {
private static final long serialVersionUID = 6732775093033061190L;
@Version
@Column(name = "OBJ_VERSION")
private Timestamp version;
@Id
@Column(name = "SSN", length = 12, nullable = false, insertable = true, updatable = true)
private String ssn;
@Column(name = "LAST_NAME", length = 50, nullable = false, insertable = true, updatable = true)
private String lastName;
@Column(name = "FIRST_NAME", length = 30, nullable = false, insertable = true, updatable = true)
private String firstName;
@Column(name = "MIDDLE_NAME", length = 30, nullable = true, insertable = true, updatable = true)
private String middleName;
@OneToOne(fetch = FetchType.LAZY, mappedBy = "person", cascade = CascadeType.ALL)
private Passport passport;
@OneToMany(fetch = FetchType.EAGER, mappedBy = "person", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<Citizenship> citizenship = new HashSet<>();
// Getters and setters left out for brevity
每个人可以拥有一张护照
@Entity
@Table(name = "PASSPORT",
uniqueConstraints = {
@UniqueConstraint(columnNames = {"SSN", "PASSPORT_NUMBER"})
}
)
@DynamicInsert(true)
@DynamicUpdate(true)
@SelectBeforeUpdate(true)
public class Passport implements java.io.Serializable {
private static final long serialVersionUID = 6732775093033061190L;
@Version
@Column(name = "OBJ_VERSION")
private Timestamp version;
@Id
@Column(name = "SSN", length = 12, nullable = false, insertable = true, updatable = true)
private String ssn;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "SSN")
@MapsId
private Person person;
@Column(name = "EXPIRATION_DATE", nullable = true, insertable = true, updatable = false)
private GregorianCalendar expirationDate;
@Column(name = "ISSUING_COUNTRY", nullable = true, insertable = true, updatable = false)
private String issuingCountry;
@Column(name = "PASSPORT_NUMBER", nullable = false, insertable = true, updatable = false)
private String passportNumber;
// Getters and setters left out for brevity
此方法有效,每个人可以拥有一个Passport,并且Passport.ssn分配了Person.ssn的值。之所以这样做是因为SSN是唯一标识符,并且避免了对链接表的需要。
每个人也可以拥有公民身份
@Entity
@Table(name = "CITIZENSHIP")
@DynamicInsert(true)
@DynamicUpdate(true)
@SelectBeforeUpdate(true)
public class Citizenship implements java.io.Serializable {
private static final long serialVersionUID = 6732775093033061190L;
@Version
@Column(name = "OBJ_VERSION")
private Timestamp version;
@EmbeddedId
private CitizenshipId citizenshipId;
@Column(name = "DATE_OF_CITIZENSHIP")
private GregorianCalendar dateOfCitizenship;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "SSN")
@MapsId("ssn")
private Person person;
// Getters and setters left out for brevity
我已经成功添加了一个有护照的人和一个没有护照的人。我添加了具有护照和双重国籍的第三人,
// This person has a passport and is a dual citizen.
person = new Person();
person.setSsn("654-89-7531");
person.setFirstName("Lois");
person.setLastName("Lane");
passport = new Passport();
passport.setExpirationDate(new GregorianCalendar());
passport.setIssuingCountry("USA");
passport.setPassportNumber("987654");
Set<Citizenship> citizenshipSet = new HashSet<>();
CitizenshipId citizenshipId = new CitizenshipId();
citizenshipId.setCountry("USA");
Citizenship c = new Citizenship();
c.setDateOfCitizenship(new GregorianCalendar());
c.setCitizenshipId(citizenshipId);
c.setPerson(person);
citizenshipSet.add(c);
citizenshipId = new CitizenshipId();
citizenshipId.setCountry("CAN");
c = new Citizenship();
c.setDateOfCitizenship(new GregorianCalendar());
c.setCitizenshipId(citizenshipId);
c.setPerson(person);
citizenshipSet.add(c);
person.setPassport(passport);
passport.setPerson(person);
session.saveOrUpdate(person);
for(Citizenship citizen : citizenshipSet) {
session.saveOrUpdate(citizen);
}
session.flush();
session.clear();
在我看来,这很奇怪/效率低下,但确实可以工作(需要改进的提示)。但是根据需要,Person.ssn被纳入公民身份。问题出在这里:
双重公民身份人士目前在美国和加拿大拥有公民身份。让我们假设这是错误的,并且此人在美国和墨西哥拥有公民身份,这意味着CitizenshipId.country需要从“ CAN”更改为“ MEX”。我已经尝试了很多类似
的代码 Criteria citCriteria = session.createCriteria(Citizenship.class);
citCriteria.add(Restrictions.eq("citizenshipId.ssn", "654-89-7531"));
List<Citizenship> citizenship = citCriteria.list();
for(Citizenship c : citizenship) {
if("CAN".equalsIgnoreCase(c.getCitizenshipId().getCountry())) {
session.evict(c);
c.getCitizenshipId().setCountry("MEX");
session.saveOrUpdate(c);
session.flush();
session.clear();
}
}
启用“ show_sql”后,即使我在调试时看到值更改,也不会执行更新。我确实尝试了一个evict(),然后设置了国家/地区,然后设置了saveOrUpdate,从而创建了一个新条目(我认为可以)。
Ph ...问题是:当将Embeddable类用作EmbeddedId时,如何更新该类的值?我觉得我已经接近了,但只想念一件事...
谢谢。
添加CitizenshipID供参考
@Embeddable
public class CitizenshipId implements Serializable {
private static final long serialVersionUID = 6732775093033061190L;
String ssn;
String country;
// Omitted getters, setters, constructors, hashcode, and equals
答案 0 :(得分:0)
您尝试过吗:
if("CAN".equalsIgnoreCase(c.getCitizenshipId().getCountry())) {
session.evict(c);
c.getCitizenshipId().setCountry("MEX");
c.getPerson().getCitizenship().add(c); // TRY ADDING THIS
session.saveOrUpdate(c);
session.flush();
session.clear();
}
答案 1 :(得分:0)
if("CAN".equalsIgnoreCase(c.getCitizenshipId().getCountry())) {
// TRY ADDING THIS ------------------------
//session.evict(c);
CitizenshipId cid = new CitizenshipId();
cid.setSsn(c.getCitizenshipId().getSsn();
cid.setCountry("MEX");
c.setCitizenshipId(cid); // references new CID -- should issue update
// -----------------------------------------
session.saveOrUpdate(c);
session.flush();
session.clear();
}
由于API中的说明,我删除了.evict:
从会话缓存中删除该实例。对实例的更改 将不会与数据库同步。此操作级联为 关联实例(如果关联映射到) Cascade =“ evict”。
答案 2 :(得分:0)
主题How to update values associated with Primary Key in Spring-JPA与Dan上面发布的关于使用旧对象ID创建新对象的内容一致。但是,主题Hibernate - update the primary key 'id' column in the table确实声明了Hibernate不允许更新主键。
这里的目标是创建一个具有(S)SSN(可能带有护照)和公民身份的人。 SSN旨在作为主键,因此我将Person映射到Passport and Citizenship,并使用SSN作为JoinColumn。
人与护照是一对一的关系,所以这不是问题。
人与人之间的关系是一对多的关系。这种关系意味着我必须创建一个可嵌入的ID。为了使每个Citizenship具有唯一性,使用SSN和Country创建了可嵌入的类CitizenshipId。
使用Hibernate - update the primary key 'id' column in the table的可接受答案,我更改了
Criteria citCriteria = session.createCriteria(Citizenship.class);
citCriteria.add(Restrictions.eq("citizenshipId.ssn", "654-89-7531"));
List<Citizenship> citizenship = citCriteria.list();
for(Citizenship c : citizenship) {
if("CAN".equalsIgnoreCase(c.getCitizenshipId().getCountry())) {
session.evict(c);
c.getCitizenshipId().setCountry("MEX");
session.saveOrUpdate(c);
session.flush();
session.clear();
}
}
到
Query query=session.createQuery("update Citizenship set country = :country1 where ssn = :ssn and country = :country2")
.setString("country1", "MEX").setString("ssn", "654-89-7531").setString("country2", "CAN");
query.executeUpdate();
确实发生了更新。无法通过典型代码进行更新(使用条件来获取数据,对其进行更新,然后调用saveOrUpdate),但是能够通过查询进行更新对我来说并没有多大意义。我知道,密钥管理比最好的情况更多地留给数据库,但是当使用唯一值(例如SSN)时,就不需要另一个密钥。如果在代码中没有生成策略的情况下标识了ID,则说明可以更新ID ... JMHO。
感谢Dan的想法。我希望这个主题及其参考对其他人有帮助。