簡體   English   中英

更新可嵌入類中的值

[英]Updating values in an Embeddable class

這就是我想要做的...我有一個人

@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,從而創建了一個新條目(我認為可以)。

ew ...問題是:當該類用作EmbeddedId時,如何更新Embeddable類中的值? 我覺得我已經接近了,但只想念一件事...

謝謝。

添加CitizenshipID供參考

@Embeddable
public class CitizenshipId implements Serializable {

    private static final long serialVersionUID = 6732775093033061190L;

    String ssn;
    String country;

// Omitted getters, setters, constructors, hashcode, and equals

你有沒有嘗試過:

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();
}
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”映射的,則此操作將級聯到關聯的實例。

主題如何更新Spring-JPA中與主鍵相關的值與 Dan上面發布的內容有關,即有關使用舊對象ID創建新對象的內容。 但是,主題Hibernate-更新表中的主鍵'id'列確實表明Hibernate不允許更新主鍵。

此處的目標是創建一個具有SSN(可能具有護照)和公民身份的人。 SSN旨在作為主鍵,因此我將Person映射到Passport and Citizenship,並將SSN用作JoinColumn。

護照的人是一對一的關系,所以這不是問題。

人與人之間的關系是一對多的關系。 這種關系意味着我必須創建一個可嵌入的ID。 為了使每個Citizenship唯一,使用SSN和Country創建了可嵌入的類CitizenshipId。

使用可接受的Hibernate答案-更新表中的主鍵“ id”列,我更改了

    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的想法。 希望本主題及其參考對其他人有幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM