0

I have a PUT call that, via @RequestBody, will map the payload to the below Object:

@Entity @Table(uniqueConstraints = @UniqueConstraint(columnNames = {"clientId", "reasonCode"})) public class DeviceInfo implements Serializable { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private long id; private int clientId; private String reasonCode; private int deviceValue; ... Getters and Setters here .... } 

For the DAO layer I have this simple Interface

public interface DeviceInfoDao extends JpaRepository<DeviceInfo, Long> { } 

which using Spring gets @Autowired into my Service layer and saves the Object to the DB with

deviceInfo = deviceInfoDao.save(deviceInfo); 

The issue I am running into is, I could later have another PUT call where the payload is the same except this time the deviceValue is different. Currently it will throw an Exception because the @UniqueConstraint was violated.

However, what I would prefer is that an update happens when DeviceInfoDao.save() gets called rather than an Exception getting thrown. I am new to JPA and Hibernate so if someone could please give "best practice" or the cleanest way to do this I would greatly appreciate it.

As a side note -

  1. I know throwing an Exception (or sending some kind of error) and forcing the user to use the PATCH HTTP method would probably be the best practices scenario here but requirements dictate I do it this way.

  2. The caller won't know the auto-generated id value that was produced so having them send that on the next call is not an option.

2 Answers 2

2

There is no out-of-the-box mechanism that will do this for you. A common way to handle this situation is to first do a search by input parameters, and depending on the output do a save or update

DeviceInfo deviceInfo = deviceInfoDao.findByClientIdAndReasonCode(clientId, reasonCode); if (deviceInfo == null) { deviceInfo = deviceInfoDao.save(deviceInfo); } else { deviceInfo.setDeviceValue(deviceValue); deviceInfoDao.update(deviceInfo); } 
Sign up to request clarification or add additional context in comments.

Comments

1

The way I ended up implementing this is slightly different than the accepted answer and I put here in case it may help anyone else.

As suggested I added this line to my DeviceInfoDao Interface:

DeviceInfo findByClientIdAndReasonCode(clientId, reasonCode); 

Then my Service layer looks something like this:

public DeviceInfo saveOrUpdateDeviceInfo(DeviceInfo deviceInfo) { DeviceInfo previousDeviceInfo = deviceInfoDao.findByClientIdAndReasonCode(clientId, reasonCode); if(previousDeviceInfo != null) { deviceInfo.setId(previousDeviceInfo.getId()); } // Will also update if exists deviceInfo = deviceInfoDao.save(deviceInfo); return deviceInfo } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.