Home > front end >  How to make Spring (Hibernate) instantiate child entities in single table inheritance scenario as th
How to make Spring (Hibernate) instantiate child entities in single table inheritance scenario as th

Time:01-13

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).

  • Related