简体   繁体   中英

CRUD Repository: Override save to Implement exists

I have an interface that extends CrudRepository, and every time I save an object with a key that already exists, it overwrites the existing object with the new one. How can I override save so that it checks if an object with that key already exists?

I have already tried the following, but it did not work:

public interface CustomRepo {

    public Channel save(Channel channel);

}


public class RepositoryImpl implements CustomRepo {

    @Autowired
    private DynamoDBMapper  mapper;

    public Channel save(Channel channel){
        channel.setId(UUID.randomUUID().toString());
        DynamoDBSaveExpression saveExpression = new DynamoDBSaveExpression();
        Map<String, ExpectedAttributeValue> expectedAttributes = 
                ImmutableMap.<String, ExpectedAttributeValue>builder()
                    .put(channel.getUrl(), new ExpectedAttributeValue(false))
                    .put(channel.getTitle(), new ExpectedAttributeValue(false))
                    .build();
        saveExpression.setExpected(expectedAttributes);
        saveExpression.setConditionalOperator(ConditionalOperator.AND);

        try {
            mapper.save(channel, saveExpression);
        } catch (ConditionalCheckFailedException e) {
            System.err.println("Item with URL {} already exists. Cannot overrwrite."+ channel.getUrl());
            System.err.println(e.getMessage());
        }
        return channel;

    }

public interface ChannelRepository extends CrudRepository<Channel, String>, CustomRepo {
    @EnableScan
    List<Channel> findByTitle(String title);

    @Override
    @EnableScan
    List<Channel> findAll();

    List<Channel> findByUrl(String url);

}

Problem: I understand the problem statement as "all the existing non-key attributes are replaced with new value" rather than the URL and TITLE attributes that you are trying to update.

There are two ways to resolve this problem without overriding the save() method.

1) SaveBehavior can be set appropriately to update the attributes accordingly. In your code, you have used the default UPDATE save behavior. You can use UPDATE_SKIP_NULL_ATTRIBUTES save behavior, so that it doesn't update the NULL attributes in model object (in your case, it is channel).

You can also look at APPEND_SET which is a further extension of UPDATE_SKIP_NULL_ATTRIBUTES for SET data type.

Sample Code:-

DynamoDBMapperConfig dynamoDBMapperConfig = new DynamoDBMapperConfig(SaveBehavior.UPDATE_SKIP_NULL_ATTRIBUTES);     
DynamoDBMapper dynamoDBMapper = new DynamoDBMapper(dynamoDBClient, dynamoDBMapperConfig);
dynamoDBMapper.save(order);

UPDATE (default) : UPDATE will not affect unmodeled attributes on a save operation and a null value for the modeled attribute will remove it from that item in DynamoDB. Because of the limitation of updateItem request, the implementation of UPDATE will send a putItem request when a key-only object is being saved, and it will send another updateItem request if the given key(s) already exists in the table.

APPEND_SET treats scalar attributes (String, Number, Binary) the same as UPDATE_SKIP_NULL_ATTRIBUTES does. However, for set attributes, it will append to the existing attribute value, instead of overriding it. Caller needs to make sure that the modeled attribute type matches the existing set type, otherwise it would result in a service exception.

UPDATE_SKIP_NULL_ATTRIBUTES is similar to UPDATE, except that it ignores any null value attribute(s) and will NOT remove them from that item in DynamoDB. It also guarantees to send only one single updateItem request, no matter the object is key-only or not.

DynamoDBMapperConfig SaveBehavior

2) The UpdateItemSpec with table.updateItem can be used to update few attributes for a specific key

UpdateItemSpec Example

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM