activejdbcjavalite

In ActiveJDBC how to update value of one of the Composite Key fields?


I am using ActiveJDBC. I have a table that is made up of a composite key (parentId, childId, effStartDate). I have a new requirement to allow the updating of the effStartDate field. When I tried to update the field and save, it errors out. Is there an appropriate way to update this using the ORM or a raw SQL approach in ActiveJDBC?

Current approach:

mymodel.setEffStartDate(newStartDate);
mymodel.saveIt();

Updated to provide more details. Here's the exact code:

try {
    ri.setEffStartDate(ld);
    boolean didItSave = ri.saveIt(user);
    System.out.println("here - " + didItSave);
} catch(Exception e) {
    System.out.println("Exception: " + e);
}

When the saveIt runs, it doesn't error out. However, it returns FALSE and nothing gets updated in the database. So I misused "errors" in my earlier statement. I should have said it just doesn't do anything.

We are using Oracle database.

The model class trying to update:

                        package com.brookdale.model;

                    import java.time.LocalDate;

                    import org.javalite.activejdbc.annotations.BelongsTo;
                    import org.javalite.activejdbc.annotations.BelongsToParents;
                    import org.javalite.activejdbc.annotations.CompositePK;
                    import org.javalite.activejdbc.annotations.Table;
                    import org.javalite.activejdbc.validation.ValidationException;

                    import com.brookdale.model.activejdbc.CecilModel;

                    @Table("MONET.CONTACTREL")
                    @CompositePK({ "parentContactID", "childContactID", "contactRelTypeID", "effStartDate" })

                    @BelongsToParents({
                        @BelongsTo(foreignKeyName="relationshipId",parent=Relationship.class),
                        @BelongsTo(foreignKeyName="contactRelTypeID",parent=ContactRelType.class),
                    //  @BelongsTo(foreignKeyName="parentContactID",parent=Contact.class),
                    //  @BelongsTo(foreignKeyName="childContactID",parent=Contact.class),
                        @BelongsTo(foreignKeyName="childContactID",parent=Contact.class),
                        @BelongsTo(foreignKeyName="childContactID",parent=ResidentContactDetail.class)
                    })
                    public class ContactRel extends CecilModel {
                        private ResidentContactDetail emergResidentContactDetail;
                        private ResidentContactDetail healthResidentContactDetail;
                        private ResidentContactDetail finResidentContactDetail;
                        private int emergresidentind = 0;

                        public Long getParentContactID() {
                            return getLong("parentContactID");
                        }
                        public void setParentContactID(Long parentContactID) {
                            set("parentContactID",parentContactID);
                        }
                        public Long getChildContactID() {
                            return getLong("childContactID");
                        }
                        public void setChildContactID(Long childContactID) {
                            set("childContactID",childContactID);
                        }   
                        public LocalDate getEffStartDate() {
                            return getLocalDate("effStartDate");
                        }
                        public void setEffStartDate(LocalDate effStartDate) {
                            setLocalDate("effStartDate",effStartDate);
                        }
                        public LocalDate getEffEndDate() {
                            return getLocalDate("effEndDate");
                        }
                        public void setEffEndDate(LocalDate effEndDate) {
                            setLocalDate("effEndDate",effEndDate);
                        }
                        public Integer getContactRelTypeID() {
                            return getInteger("contactRelTypeID");
                        }
                        public void setContactRelTypeID(Integer contactRelTypeID) {
                            set("contactRelTypeID",contactRelTypeID);
                        }
                        public Integer getRelationshipId() {
                            return getInteger("relationshipId");
                        }
                        public void setRelationshipId(Integer relationshipId) {
                            set("relationshipId",relationshipId);
                        }
                        public Integer getParentIsPrimaryResidentInd() {
                            return getInteger("parentIsPrimaryResidentInd");
                        }
                        public void setParentIsPrimaryResidentInd(Integer parentIsPrimaryResidentInd) {
                            set("parentIsPrimaryResidentInd",parentIsPrimaryResidentInd);
                        }
                        public Integer getParentIsSecondPersonInd() {
                            return getInteger("parentIsSecondPersonInd");
                        }
                        public void setParentIsSecondPersonInd(Integer parentIsSecondPersonInd) {
                            set("parentIsSecondPersonInd",parentIsSecondPersonInd);
                        }
                        public int getCourtesyCopyInd() {
                            return getInteger("courtesyCopyInd");
                        }
                        public void setCourtesyCopyInd(Integer courtesyCopyInd) {
                            set("courtesyCopyInd",courtesyCopyInd);
                        }

                        /* Additional helper methods */
                        public Contact getParentContact() {
                            return Contact.findById(getParentContactID());
                        }
                        public Contact getChildContact() {
                            return Contact.findById(getChildContactID());
                        }

                        public int getEmergresidentind() {
                            return emergresidentind;
                        }
                        public void setEmergresidentind(int emergresidentind) {
                            this.emergresidentind = emergresidentind;
                        }
                        @Override
                        public void validate(){
                            super.validate();
                            validatePresenceOf("parentContactID", "Parent Contact is required.");
                            validatePresenceOf("childContactID", "Contact is required.");
                            validatePresenceOf("contactRelTypeID", "Resident relationship type is required.");
                            validatePresenceOf("effStartDate", "Effective Start Date is required.");
                            validatePresenceOf("relationshipid", "Relationship is required.");

                            if(this.getEffEndDate() != null) {
                                if(this.getEffEndDate().isBefore(this.getEffStartDate())) {
                                    this.addError("effenddate", "End date must be on or after the start date.");
                                }
                            }

                            if(this.hasErrors()) {
                                throw new ValidationException(this);
                            }
                        }

                    }

Our CecilModel class we are extending the Model class. package com.brookdale.model.activejdbc;

                    import java.io.IOException;
                    import java.sql.Timestamp;
                    import java.text.SimpleDateFormat;
                    import java.time.LocalDate;
                    import java.time.LocalDateTime;
                    import java.time.ZonedDateTime;
                    import java.time.format.DateTimeFormatter;
                    import java.util.ArrayList;
                    import java.util.Collection;
                    import java.util.HashMap;
                    import java.util.LinkedList;
                    import java.util.List;
                    import java.util.Map;

                    import org.apache.axis.utils.StringUtils;
                    import org.apache.log4j.Logger;
                    import org.javalite.activejdbc.Model;
                    import org.javalite.activejdbc.validation.ValidationBuilder;
                    import org.javalite.activejdbc.validation.ValidationException;
                    import org.javalite.activejdbc.validation.ValidatorAdapter;

                    import com.brookdale.core.CLArgs;
                    import com.brookdale.exception.CecilErrorsException;
                    import com.brookdale.message.CecilMessage;
                    import com.brookdale.model.Building;
                    import com.brookdale.security.bo.User;
                    import com.fasterxml.jackson.core.type.TypeReference;
                    import com.fasterxml.jackson.databind.JsonNode;
                    import com.fasterxml.jackson.databind.ObjectMapper;
                    import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

                    import oracle.sql.DATE;

                    public abstract class CecilModel extends Model {

                        final static Logger logger = Logger.getLogger(CecilModel.class);

                        private static final transient TypeReference<HashMap<String, Object>> mapType = new TypeReference<HashMap<String, Object>>() {};
                        private static final transient TypeReference<ArrayList<HashMap<String, Object>>> listMapType = new TypeReference<ArrayList<HashMap<String, Object>>>() {};
                        //add -0600 to specify cental time zone
                        private static final transient SimpleDateFormat jsonDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); 

                        private transient Map<String, Collection<Map<String, Object>>> jsonInclude = new HashMap<>();

                        public Timestamp getUpdateDateTime() {
                            return getTimestamp("updateDateTime");
                        }
                        public void setUpdateDateTime(LocalDateTime updateDateTime) {
                            set("updateDateTime",updateDateTime == null ? null : Timestamp.valueOf(updateDateTime));
                        }
                        public Timestamp getCreateDateTime() {
                            return getTimestamp("createDateTime");
                        }
                        public void setCreateDateTime(LocalDateTime createDateTime) {
                            set("createDateTime",createDateTime == null ? null : Timestamp.valueOf(createDateTime));
                        }
                        public String getUpdateUsername() {
                            return getString("updateUsername");
                        }
                        public void setUpdateUsername(String updateUsername) {
                            set("updateUsername",updateUsername);
                        }
                        public String getCreateUsername() {
                            return getString("createUsername");
                        }
                        public void setCreateUsername(String createUsername) {
                            set("createUsername",createUsername);
                        }
                        public Long getUpdateTimeId() {
                            return getLong("updatetimeid");
                        }
                        public void setUpdateTimeId(Long updateTimeId) {
                            if (updateTimeId == null)
                                setLong("updatetimeid", 1);
                            else
                                setLong("updatetimeid",updateTimeId);
                        }
                        public void incrementUpdateTimeId() {
                            Long updatetimeid = this.getUpdateTimeId();
                            if (updatetimeid == null)
                                this.setUpdateTimeId(1L);
                            else
                                this.setUpdateTimeId(updatetimeid+1L);
                        }


                        public boolean save(User user) {
                            String userId = (CLArgs.args.isAuthenabled()) ? user.getUserid() : "TEST_MODE";
                            // insert
                            java.sql.Timestamp now = java.sql.Timestamp.valueOf(java.time.LocalDateTime.now());
                            if (this.getId() == null || this.getId().toString().equals("0")) {
                                this.setId(null);
                                this.set("createDateTime", now);
                                this.set("createUsername", userId);
                                this.set("updateDateTime", now);
                                this.set("updateUsername", userId);
                                this.set("updateTimeId", 1);
                            } 
                            // update
                            else {
                                Long updatetimeid = this.getLong("updateTimeid");
                                this.set("updateDateTime", now);
                                this.set("updateUsername", userId);
                                this.set("updateTimeId",  updatetimeid == null ? 1 : updatetimeid + 1);
                            }
                            return super.save();
                        }

                        public boolean saveIt(User user) {
                            String userId = (CLArgs.args.isAuthenabled()) ? user.getUserid() : "TEST_MODE";
                            // insert
                            java.sql.Timestamp now = java.sql.Timestamp.valueOf(java.time.LocalDateTime.now());
                            if (this.isNew()) {
                                this.setId(null);
                                this.set("createDateTime", now);
                                this.set("createUsername", userId);
                                this.set("updateDateTime", now);
                                this.set("updateUsername", userId);
                                this.set("updateTimeId", 1);
                            } 
                            // update
                            else {
                                Long updatetimeid = this.getLong("updateTimeid");
                                this.set("updateDateTime", now);
                                this.set("updateUsername", userId);
                                this.set("updateTimeId",  updatetimeid == null ? 1 : updatetimeid + 1);
                            }
                            return super.saveIt();
                        }

                        public boolean saveModel(User user, boolean insert) {
                            return saveModel(user.getUserid(), insert);
                        }

                        public boolean saveModel(String userId, boolean insert) {
                            userId = (CLArgs.args.isAuthenabled()) ? userId : "TEST_MODE";
                            if(insert){
                                return this.insertIt(userId);
                            }else{
                                return this.updateIt(userId);
                            }
                        }

                        public boolean insertIt(String user) {
                            user = (CLArgs.args.isAuthenabled()) ? user : "TEST_MODE";
                            // insert
                            java.sql.Timestamp now = java.sql.Timestamp.valueOf(java.time.LocalDateTime.now());     
                            this.set("createDateTime", now);
                            this.set("createUsername", user);
                            this.set("updateDateTime", now);
                            this.set("updateUsername", user);
                            this.set("updateTimeId", 1);
                            this.validate();
                            if(this.hasErrors()){
                                throw new ValidationException(this);
                            }
                            boolean inserted = super.insert();
                            if (!inserted)
                                throw new CecilErrorsException(new CecilMessage().error("Failed to insert " + this.getClass().getSimpleName()));
                            return inserted;
                        }

                        public boolean updateIt(String user) {
                            user = (CLArgs.args.isAuthenabled()) ? user : "TEST_MODE";
                            // update
                            java.sql.Timestamp now = java.sql.Timestamp.valueOf(java.time.LocalDateTime.now());     
                            this.set("updateDateTime", now);
                            this.set("updateUsername", user);
                            this.incrementUpdateTimeId();
                            this.validate();
                            if(this.hasErrors()){
                                throw new ValidationException(this);
                            }
                            boolean updated = super.save();
                            if (!updated)
                                throw new CecilErrorsException(new CecilMessage().error("Failed to update " + this.getClass().getSimpleName()));
                            return updated;
                        }

                        @Override
                        public <T extends Model> T set(String field, Object value) {
                            if (value instanceof LocalDate) {
                                return super.set(field, java.sql.Date.valueOf((LocalDate)value));
                            } else if (value instanceof LocalDateTime) {
                                return super.set(field, java.sql.Timestamp.valueOf((LocalDateTime)value));
                            } else {
                                return super.set(field, value);
                            }
                        }
                        public LocalDate getLocalDate(String field) {
                            if (field == null || "".equals(field))
                                return null;
                            else {
                                java.sql.Date d = getDate(field);
                                return d == null ? null : d.toLocalDate();
                            }
                        }
                        public void setLocalDate(String field, LocalDate value) {
                            if (value == null)
                                setDate(field, null);
                            else
                                setDate(field, java.sql.Date.valueOf(value));
                        }
                        public LocalDateTime getLocalDateTime(String field) {
                            java.sql.Timestamp d = getTimestamp(field);
                            return d == null ? null : d.toLocalDateTime();
                        }
                        public void setLocalDateTime(String field, LocalDateTime value) {
                            if (value == null)
                                setTimestamp(field, null);
                            else
                                setTimestamp(field, java.sql.Timestamp.valueOf(value));
                        }

                    }

Solution

  • The method Model.saveIt() will save the model attributes to a table if such a record (according to primary keys) already exists. If you are setting the primary keys to values not found in the database, this method will exit without doing much.

    Additionally, there are a few issues in your code that are not idiomatic of JavaLite.

    Update: based on your comment below, the framework will update the record if it is not "new", meaning if the PK or Composite Keys are not null, it will assume that you know what you are doing and will expect to find that record in the table by primary or composite keys, therefore if they key(s) are set and not null, it will always generate an UPDATE rather than insert. As a result, if you are setting primary keys to values not present in the table, the saveIt() or save() will do nothing. Please, see http://javalite.io/surrogate_primary_keys for more information.

    Additionally, you can enable Logging to see what SQL it generates.