Hibernate lazy attribute loading. False positive field detection with @DynamicUpdate

Viewed 150

I have a Hibernate entity with a lazy attribute.

@AllArgsConstructor
@NoArgsConstructor
@Getter
@Entity
@Table(name = "rule", schema = "mariott_rule")
@DynamicUpdate // this is important
public class Rule {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "rule_id")
    private Long id;

    @Column(name = "switch")
    private boolean switched;

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

    private String description;

    @Column(name = "date_update")
    private ZonedDateTime dateUpdated;

    @Column(name = "param_values", columnDefinition = "text")
    @Convert(converter = RuleParamValuesAttributeConverter.class)
    @Basic(fetch = LAZY)
    private RuleParamValuesValidatedEntity paramValues;
}

And I have two methods that can either switch off or switch on the rule. Before switching the rule on we have be sure that paramValues are valid. That's why we fetch them with a separate query. But for the vice-versa operation it's not important. So, paramValues are not loaded in this case.

But here comes the strange part. The switching on operation generates the expected SQL.

validateParamValues(rule.getParamValues());
ruleRepository.saveAndFlush(
    rule.asBuilder()
        .switched(true)
        .dateUpdated(now)
        .build();
);
update mariott_rule.rule set date_update=?, switch=? where rule_id=?

Meantime the switching off operation adds paramValues to result SQL and assigns its value to "null" (the string value of null word).

// NO param values fetching
ruleRepository.saveAndFlush(
    rule.asBuilder()
        .switched(false)
        .dateUpdated(now)
        .build();
);
update mariott_rule.rule set date_update=?, param_values=?, switch=? where rule_id=?
binding parameter [1] as [TIMESTAMP] - [2021-04-09T08:10:28.423406Z]
binding parameter [2] as [VARCHAR] - [null]
binding parameter [3] as [BOOLEAN] - [false]
binding parameter [4] as [BIGINT] - [1]

Perhaps it's something about RuleParamsValuesAttributeConverter.class.

I removed the Basic(fetch = LAZY). Though it did help that's not what I want. Any ideas?

P.S. BTW, when I removed Basic(fetch = LAZY) it seems that @DynamicUpdate stopped to work either.

EDIT:

Here is the JsonAttributeConverter and RuleParamValuesAttributeConverter

@Slf4j
@RequiredArgsConstructor
public abstract class JsonAttributeConverter<A> implements AttributeConverter<A, String> {
    private final ObjectMapper objectMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    private final Class<A> entityClass;
    private final String dbColumnName;
    private final A defaultValue;

    @Override
    public String convertToDatabaseColumn(A attribute) {
        try {
            return objectMapper.writeValueAsString(attribute);
        } catch (Exception e) {
            throw new ConvertException(String.format("Cannot convert %s to string", entityClass.getSimpleName()), e);
        }
    }

    @Override
    public A convertToEntityAttribute(String dbData) {
        try {
            return objectMapper.readValue(dbData, entityClass);
        } catch (Exception e) {
            if (log.isDebugEnabled()) {
                log.warn(
                    String.format(
                        "Cannot convert database column %s to the %s. The default value shall be used",
                        dbColumnName,
                        entityClass.getSimpleName()),
                    e
                );
            }
            return defaultValue;
        }
    }
}
@Converter
public class RuleParamValuesAttributeConverter extends JsonAttributeConverter<RuleParamValuesValidatedEntity> {
    public RuleParamValuesAttributeConverter() {
        super(RuleParamValuesValidatedEntity.class, "mariott_rule.rule.param_values", RuleParamValuesValidatedEntity.getInvalidInstance());
    }
}
0 Answers
Related