2

Contact Interceptor attached with hibernate configuration

public class ContactInterceptor extends EmptyInterceptor {

    /**
     */
    private static final long serialVersionUID = -2000639365689865828L;

    @Override
    public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {
        if (entity instanceof LastModifiable) {
            if (!Arrays.equals(currentState, previousState)) {
                int index = ArrayUtils.indexOf(propertyNames, "modified");
                if (index > 0) {
                    currentState[index] = new Date();
                    return super.onFlushDirty(entity, id, currentState, previousState, propertyNames, types);
                }
            }
        }
        return false;
    }
  }

Address model

public class Address extends Model {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue
    @Column(name = "id")
    private Long              id;

    @OneToOne
    @JoinColumn(referencedColumnName = "id", name = "contact_id")
    private Contact           contact;

    @Column(name = "address")
    private String            address1;

    @Column(name = "address2")
    private String            address2;

    @Column(name = "city")
    private String            city;

    @Column(name = "country")
    private String            country;

    @Column(name = "state")
    private String            state;

    @Column(name = "zipcode")
    private String            zipcode;

    @Column(name = "company")
    private String            company;

    @Override
    public Long getId() {
        return this.id;
    }

    @Override
    public void setId(Long val) {
        this.id=val;
    }

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "created", columnDefinition = "DATETIME")
    public Date getCreated() {
        return created;
    }

    public void setCreated(Date created) {
        this.modified = this.created = created;
    }

    private Date created = null;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "modified", columnDefinition = "DATETIME")
    public Date getModified() {
        return modified;
    }

    public void setModified(Date modified) {
        this.modified = modified;
    }

    private Date modified;

}

Contact.java

public  class Contact extends Model {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "id")
    private Long              id;

    @Column(name = "first_name")
    private String            firstName;

    @Column(name = "last_name")
    private String            lastName;

    @Transient
    private String            fullName;

    @Column(name = "email")
    private String            email;

    @Column(name = "contact")
    private String            contact;

    @JsonIgnore
    @OneToMany(mappedBy = "contact", fetch = FetchType.EAGER)
    protected Set<Address>    addresses        = new HashSet<Address>(0);

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getFullName() {
        return fullName;
    }

    public void setFullName(String fullName) {
        this.fullName = fullName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getContact() {
        return contact;
    }

    public void setContact(String contact) {
        this.contact = contact;
    }

    public Set<Address> getAddresses() {
        return addresses;
    }

    public void setAddresses(Set<Address> addresses) {
        this.addresses = addresses;
    }

@Temporal(TemporalType.TIMESTAMP)
        @Column(name = "created", columnDefinition = "DATETIME")
        public Date getCreated() {
            return created;
        }

        public void setCreated(Date created) {
            this.modified = this.created = created;
        }

        private Date created = null;

        @Temporal(TemporalType.TIMESTAMP)
        @Column(name = "modified", columnDefinition = "DATETIME")
        public Date getModified() {
            return modified;
        }

        public void setModified(Date modified) {
            this.modified = modified;
        }

        private Date modified;


}

Main.java

public static void main(String[] args) {
        HibernateUtility u = new HibernateUtility();
        u.beginTransaction();

        Contact c = DBService.getDBService(Contact.class).load(112L);

        Address add = new Address();
        add.setAddress1("Dummy Address 1");
        add.setCity("AHMD");
        add.setState("GUJ");
        add.setCreated(new Date());
        add.setCountry("INR");
        add.setContact(c);
        c.getAddresses().add(add);
//        c.setModified(new Date());

        u.endTransaction();
    }

As we know that onFlushDirty is Called when an object is detected to be dirty jboss Doc

But when I add address in in Contact which has type collection, during debug I can see address is dirty (as new record is going to insert) but why contact is not dirty here ?

Does hibernate don't detect dirty object in case of collection modification ? or am I missing something ?

My Primary Concern is when Child is dirty or modified parent modified date should also be change.

Santosh Giri
  • 109
  • 12

2 Answers2

2

Dirty objects are ones that get saved/updated on flush, not the objects that are associated with them. Otherwise all objects associated with Contacts should also be considered dirty because the contacts that they contain have "changed", then all objects associated with those objects etc. effectively meaning that a large portion of the database could get considered dirty because you add a new address.

The only solution is to manually write the logic that executes when associated objects change, as Hibernate cannot know an application's specific business rules.

Dragan Bozanovic
  • 23,102
  • 5
  • 43
  • 110
0
  1. You forgot to call em.persist(address), dirty checking works just for managed entities.
  2. Didn't you forget to add hibernate.ejb.interceptor.session_scoped=package.ContactInterceptor property??
  3. to manage modified and created date just use @CreationTimestamp, @UpdateTimestamp and Hibernate does the magic for you :) see Creation timestamp and last update timestamp with Hibernate and MySQL
Community
  • 1
  • 1
idmitriev
  • 4,619
  • 4
  • 28
  • 44
  • @UpdateTimestamp works only when I change anything in Contact.java entity but if I'm adding new address, it is not modifying Contact – Santosh Giri Jan 02 '17 at 06:52
  • agree, you should do it manually, like add method that changes modified date for address entity. – idmitriev Jan 02 '17 at 12:24
  • definitely manual is the worst case scenario. What I want here is to have single controller to manage such event. Is there a way to check whether Object is dirty in DefaultSaveOrUpdaeEvent ? – Santosh Giri Jan 09 '17 at 07:18
  • @SantoshGiri Actually you can catch it in public void onCollectionUpdate(Object collection, Serializable key) in Interceptor. When you add a new address to contact's address you will be able to handle it as you wish. – idmitriev Jan 10 '17 at 10:19