Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't fetch related entity when retrieving an entity for viewing/updating #23917

Closed
1 task done
hide212131 opened this issue Oct 19, 2023 · 9 comments · Fixed by #23960
Closed
1 task done

Can't fetch related entity when retrieving an entity for viewing/updating #23917

hide212131 opened this issue Oct 19, 2023 · 9 comments · Fixed by #23960

Comments

@hide212131
Copy link
Contributor

hide212131 commented Oct 19, 2023

Overview of the issue

In JDL:

relationship OneToMany {
  Department to Employee {department}
}

When retrieving the Employee entity for viewing or updating, the related Department entity cannot be fetched.

JSON in HTTP Response:

{
  "id": 1,
  "firstName": "Jun",
  "salary": 11169,
  "hireDate": "2023-10-05T15:55:00Z",
  "department": null
}

As a result, the department information is not displayed.

cant_fetch_entity
Motivation for or Use Case

The expected operation does not occur, such as the disappearance of a value that should have been registered.

Reproduce the error

Generated in JDL, including related (at least, occurs in OneToOne, ManyToOne, OneToMany)

Related issues

It appears that the fetch strategy is related to this issue.
#20285
#19791 (comment)

Suggest a Fix

Removing (fetch = FetchType.LAZY) from the entity serves as a temporary workaround.
For example:

Employee.java:

    @ManyToOne(fetch = FetchType.LAZY) // change to @ManyToOne
    @JsonIgnoreProperties(value = { "employees" }, allowSetters = true)
    private Department department;

JSON in HTTP Response:

{
  "id": 1,
  "firstName": "Jun",
  "salary": 11169,
  "hireDate": "2023-10-05T15:55:00Z",
  "department": {
    "id": 3,
    "departmentName": "Courageous Now Freelance"
  }
}

A more appropriate long-term solution would involve using Entity Graphs.

JHipster Version(s)

8.0.0-rc.1

JHipster configuration, a .yo-rc.json file generated in the root folder
.yo-rc.json file
{
  "generator-jhipster": {
    "applicationType": "monolith",
    "authenticationType": "jwt",
    "baseName": "myApp",
    "buildTool": "maven",
    "cacheProvider": "ehcache",
    "clientFramework": "react",
    "clientTestFrameworks": [],
    "clientTheme": "none",
    "creationTimestamp": 1696591837279,
    "databaseType": "sql",
    "devDatabaseType": "h2Disk",
    "devServerPort": 9060,
    "enableGradleEnterprise": null,
    "enableHibernateCache": true,
    "enableSwaggerCodegen": false,
    "enableTranslation": true,
    "entities": [
      "Employee",
      "Department"
    ],
    "gradleEnterpriseHost": null,
    "jhipsterVersion": "8.0.0-beta.3",
    "languages": [
      "ja",
      "en",
      "fr"
    ],
    "lastLiquibaseTimestamp": 1696591957000,
    "messageBroker": false,
    "microfrontend": null,
    "microfrontends": [],
    "nativeLanguage": "ja",
    "packageName": "com.mycompany.myapp",
    "prodDatabaseType": "postgresql",
    "reactive": false,
    "searchEngine": false,
    "serverPort": null,
    "serverSideOptions": [],
    "serviceDiscoveryType": false,
    "testFrameworks": [],
    "websocket": false,
    "withAdminUi": true
  }
}
Environment and Tools

openjdk version "17.0.8" 2023-07-18
OpenJDK Runtime Environment GraalVM CE 22.3.3 (build 17.0.8+7-jvmci-22.3-b22)
OpenJDK 64-Bit Server VM GraalVM CE 22.3.3 (build 17.0.8+7-jvmci-22.3-b22, mixed mode, sharing)

git version 2.39.3 (Apple Git-145)

node: v18.17.1
npm: 9.6.7

Docker version 24.0.6, build ed223bc

JDL for the Entity configuration(s) entityName.json files generated in the .jhipster directory
JDL entity definitions
entity Employee {
  firstName String
  salary Long
  hireDate Instant
}
entity Department {
  departmentName String required
}
relationship OneToMany {
  Department{employee} to Employee
}

search Employee, Department with no

Browsers and Operating System
  • Checking this box is mandatory (this is just to show you read everything)
@hide212131
Copy link
Contributor Author

I've updated the "Suggest a Fix" section. Keeping (fetch = FetchType.LAZY) and using Entity Graphs would be a better approach.

@mshima
Copy link
Member

mshima commented Oct 20, 2023

Looks like there is another behavior change.
The id used to be returned even without the entire entity fetch.
So this conditional must be reviewed:

(relationship.ownerSide && relationship.otherEntity.primaryKey.name !== relationship.otherEntityField);

@mshima
Copy link
Member

mshima commented Oct 20, 2023

@hide212131
Copy link
Contributor Author

Certainly, setting Feature.SERIALIZE_IDENTIFIER_FOR_LAZY_NOT_LOADED_OBJECTS to true allows the ID to be fetched correctly.

public class JacksonConfiguration {
    ...
    /*
     * Support for Hibernate types in Jackson.
     */
    @Bean
    public Hibernate6Module hibernate6Module() {
        return new Hibernate6Module().configure(Feature.SERIALIZE_IDENTIFIER_FOR_LAZY_NOT_LOADED_OBJECTS, true);
    }

@hide212131
Copy link
Contributor Author

I believe one of the following solutions should be implemented before the v8 release.

  1. Use Feature.SERIALIZE_IDENTIFIER_FOR_LAZY_NOT_LOADED_OBJECTS.
    • Pros: Quick (won't hinder the v8 release)
    • Cons: It seems like a temporary solution. By chance, the setting matches the default JHipster implementation (fetching only 'id'). However, The primary intent of the view/update use case is to retrieve related information. Hence, as the implementation progresses, this option might quickly become unnecessary.
  2. Implement an EAGER-specific solution as described in this plan. I've provided a sample code using Entity Graphs.
    • Pros: This can serve as a reference implementation for those wanting to use EAGER for specific use cases.
    • Cons: Due to the need for changes to the existing server-side relationship implementation and modifications to client-side frameworks like Angular, React, and Vue, this approach is likely to be more time-consuming.

@mshima
Copy link
Member

mshima commented Oct 22, 2023

@hide212131 1. should be implemented.

Not sure about 2.

Please check the jdl:

entity Employee {
  firstName String
  salary Long
  hireDate Instant
}
entity Department {
  departmentName String required
}
relationship OneToMany {
  Department{employee} to Employee{department(departmentName)}
}

search Employee, Department with no

We need adjusts but the following jdl should work too

entity Employee {
  firstName String
  salary Long
  hireDate Instant
}
entity Department {
  departmentName String required
}
relationship OneToMany {
  @RelationshipEagerLoad Department{employee} to Employee
}

search Employee, Department with no

@hide212131
Copy link
Contributor Author

@mshima Following option 1, I can submit a PR if that's alright.

...I was surprised to learn about the @RelationshipEagerLoad annotation, as I couldn't find it in either the documentation or the source code. Does JDL's annotation have a mechanism to directly modify any specific properties of the generator?

@mshima
Copy link
Member

mshima commented Oct 22, 2023

Every annotation will be loaded to the model.
This behavior exists for quite some time.
But the preparation process may override them.
With the mutateData approach makes much easier to don’t override custom data.

There is so many customizations possible that it’s difficult to document everything.
I am preparing a documentation for notable customizations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants