Implementing Polymorphic Queries with Inheritance in a Database Repository

Hello,

I have an entity called “Parent” with two fields:

  • firstField
  • secondField

I also have two entities, “Child1” and “Child2”, both extending the “Parent” entity. “Child1” has an additional field called “thirdField,” and “Child2” has an additional field called “fourthField.”

These entities are stored in the same database table, where all four fields are present.

I would like to create a database query using a repository (or DataManager, if applicable). Initially, I want to query the “Parent” entity using a request like “SELECT p FROM Parent p WHERE firstField = :value.” In the future, I would like to cast the retrieved “Parent” object to either “Child1” or “Child2” and access the specific fields of each child entity.

However, when I attempt to do this, I encounter an exception stating:
Caused by: java.lang.IllegalStateException: Cannot get unfetched attribute [thirdField] from detached object com.example.entity.Child1-ad5ba90f-1a28-6faf-4bb0-2b0aa22819fc [detached].

Can you please help me understand how to achieve this functionality?

3 Likes

Hi,

As an option you an fetch missing attributes using DataManager, e.g.:

@Autowired
    private DataManager dataManager;

    @Install(to = "parentsTable.child1Field", subject = "columnGenerator")
    private Component parentsTableChild1FieldColumnGenerator(Parent entity) {
        if (entity instanceof Child1) {
            Child1 child1 = dataManager.load(Id.of(entity.getId(), Child1.class))
                    .fetchPlan(fetchPlanBuilder -> fetchPlanBuilder.add("child1Field"))
                    .one();
            return new Table.PlainTextCell(child1.getChild1Field());
        }

        return null;
    }

    @Install(to = "parentsTable.child2Field", subject = "columnGenerator")
    private Component parentsTableChild2FieldColumnGenerator(Parent entity) {
        if (entity instanceof Child2) {
            Child2 child2 = dataManager.load(Id.of(entity.getId(), Child2.class))
                    .fetchPlan(fetchPlanBuilder -> fetchPlanBuilder.add("child2Field"))
                    .one();
            return new Table.PlainTextCell(child2.getChild2Field());
        }

        return null;
    }

Regards,
Gleb

Thanks for your advice, Gleb!

However, the main goal is to optimize the code and minimize the number of database queries. Currently, I have implemented a solution that requires separate repositories for each entity and performs individual queries to the database for each of them. Unfortunately, this approach still involves three separate requests, which does not fully address my requirement for a single-database request solution.

Therefore, I am still seeking a solution that can achieve the desired functionality with a single query to the database.