I have a problem when saving columns that were set to null. I’ll give a simple example. Let’s start with the following entity classes. I’ll skip a thing or two to keep this post short.
@MappedSuperclass
public abstract class AbstractEntity implements Serializable {
@Id
private Long id;
...
}
@MappedSuperclass
public abstract class AbstractElement extends AbstractEntity {
...
@Column(length = 80)
private String description;
...
}
@Entity
@Table(name = "my_element")
public class MyElement extends AbstractElement {
...
@Column(precision = 38, scale = 18)
private Double height;
...
}
I add to this a repository:
@Repository
public interface MyElementRepository extends JpaRepository<MyElement, Long> {}
DTOs are defined in a service package:
public abstract class AbstractDto implements Serializable {
private Long id;
...
}
public abstract class AbstractElementDto extends AbstractDto {
...
private String description;
...
}
public class MyElementDto extends AbstractElementDto {
...
private Double height;
...
}
Mapping between DTOs and entities is done using Dozer. A DTO is modified from a Java FX UI. A service has been defined between UI and persistence to save modified entities.
@Service
@Transactional
public class MyElementService {
@Autowired MyElementRepository myElementRepository;
...
public List<MyElementDto> save(List<MyElementDto> dtosToSave) {
List<MyElementDto> results = Collections.emptyList();
if (dtosToSave != null && !dtosToSave.empty()) {
Iterable<MyElement> entities = convertDtosWithDozer(dtosToSave);
List<MyElement> savedEntities = myElementRepository.saveAll(entities);
results = convertEntitiesWithDozer(savedEntities);
}
return results;
}
The problem is that if I set description
to null
in the interface, the change is not stored in the database. It’ll work fine with any non null values. Same problem with the height
column.
Now, let’s define another entity:
@Entity
@Table(name = "my_other_element")
public class MyElement extends AbstractEntity {
...
@Column(length = 80)
private String description;
...
}
Equivalent repository, dto ans service are also defined. Now, what troubles me here is that description
can be set to null
in MyOtherEntity
. The major difference between MyEntity
and MyOtherEntity
: an extra level of @MappedSuperClass
. It’s important to mention that these columns are nullable in the database.
I’m aware that entities converted with Dozer are detached. But why can description be set to null in one case but not in the other? If I load a copy of my first entity from my database and set its description
to null
, it’ll work because I modified an attached entity.
For fun, I ran debugger into org.hibernate.type.TypeHelper.replace(Object[] original, Object[] target, Type[] types, SharedSessionContractImplementor session, Object owner, Map copyCache)
. The interesting part is that original
contains non null columns of the entity to be saved, when I want to save a detached copy of MyEntity
. This means that setting description
to null
is ignored.
Any ideas what’s going on? How can a null
value be saved in MyEntity
? Will I have to load it first? I thought JPA was taking care of this.
Regards
Francois