Recently I started getting Hibernate's HHH000179: Narrowing proxy to class
warning when attempting to delete child entites (inheritance) that contain other relations.
This led me to learning that Hibernate proxies are created for each entity separately, even if such entity is an abstract base entity (not @MappedSuperclass
, but just abstract @Entity
) - that is even if base entity class will never exist on its own.
Consider structure of attributes:
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Table(...)
public abstract class Attribute { ...ids and common fields... }
@Entity
@DiscriminatorValue("V")
public class AttributeValued extends Attribute
{
@OneToMany( mappedBy = "attribute",
cascade = CascadeType.ALL,
orphanRemoval = true)
private Set<Value> values = new LinkedHashSet<>();
}
With Spring JPA i have repository such as:
interface AttributeRepository extends JpaRepository<Attribute, Long> {}
Consider given some id that is known to be of type AttributeValued
I run this:
Attribute a = this.attributeRepository.getReferenceById(id);
if (a instanceof AttributeValued)
{
System.out.println("VALUED");
}
else
{
System.out.println("OTHER");
}
This prints 'OTHER' while I'd expect it to print VALUED.
That means that Spring/Hibernate instantiated #getReferenceById
to base class Attribute
(or rather it's Hibernate proxy).
Is there a way for Spring/Hibernate to return proxy of actual entity (AttributeValued
) when using common JpaRepository<Attribute>
?
Because of this behivior if I do something like this:
// id is known to be of type AttributeValued
Attribute a = this.attributeRepository.getReferenceById(id);
this.attributeRepository.delete(a);
Hibernate will strike me with HHH000179: Narrowing proxy to class AttributeValued
because variable a
is proxy of Attribute
while delete(a)
will create another representation of the same row as proxy of AttributeValued
, because of AttributeValued.values
relation having:
cascade = CascadeType.ALL
orphanRemoval = true
So now I have proxy of Attribute
and proxy of AttributeValued
(I think).
CodePudding user response:
You can use @Embedded annotation on Child entity so that child and parent entities will form a single table in database You can read more about this in official documentation https://www.baeldung.com/jpa-embedded-embeddable
CodePudding user response:
Okay, so problem was absolutely elsewhere than I thought.
#getReferenceById
is JpaRepository
method.
which I used basically everywhere in my whole project (since Hibernate is Jpa and I assumed it's the correct way).
Turns out that querying with it is for some reason not polymorphic and returns proxy of Attribute
, even if row is known to represent AttributeValued
(with @DiscriminatorValue("V")
).
#findById(id)
is a CrudRepository
method and it actually is polymorphic and returns proxy of AttributeValued
, thus when I use #delete(id)
later, I will not get problems like in original question (two proxies for the same row and warning HHH000179: Narrowing proxy to class
).