jhipster / generator-jhipster

JHipster is a development platform to quickly generate, develop, & deploy modern web applications & microservice architectures.
https://www.jhipster.tech
Apache License 2.0
21.47k stars 4.02k forks source link

Misconceptions on how Bi-Directional Relationships Work or Should Work #15388

Closed hepaestus closed 10 months ago

hepaestus commented 3 years ago
Overview of the issue

In many projects I am trying to create bi-directional relationships and they are not behaving as I expect them to. My understanding is probably the whole problem here but I think I am justified in not understanding what is happening under the hood here. When I see that relationships are bidirectional, I assume some things such as:

I have created a test project to replicate my issues. I hope I am not doing something weird or wrong. I want to thank You for taking time to look at this.

Motivation for or Use Case

I am confused about what syntax produces what results. If someone could be clearer in the documentation it would be great. For Example, in the test project, I have an Author object the can have many books. The Book should be able to KNOW their Author which should have a Set of books (ie. Bi-Directional).

relationship OneToMany {
    // Expecting Bi-Directional relationship
    // Author should have a SET of books and the BOOK has one Author
    Author{books(name)} to Book{author(name)}
}

The above JDL works as I expect with the exception that the Author does not list their books on the detail page. No queries are created for the Author object to have the books in the Repository file. Am I missing something here?

File: src/main/java/com/hepaestus/testproject/repository/AuthorRepository.java
 package com.hepaestus.testproject.repository;
 import com.hepaestus.testproject.domain.Author;
 import java.util.List;
 import java.util.Optional;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.jpa.repository.*;
 import org.springframework.data.repository.query.Param;
 import org.springframework.stereotype.Repository;
 /**
  * Spring Data SQL repository for the Author entity.
  */ 
 @Repository
 public interface AuthorRepository extends JpaRepository {
     @Query(
        value = "select distinct author from Author author left join fetch author.echoes left join fetch author.friends",
        countQuery = "select count(distinct author) from Author author"
    )
    Page findAllWithEagerRelationships(Pageable pageable);

    @Query("select distinct author from Author author left join fetch author.echoes left join fetch author.friends")
    List findAllWithEagerRelationships();

    @Query("select author from Author author left join fetch author.echoes left join fetch author.friends where author.id =:id")
    Optional findOneWithEagerRelationships(@Param("id") Long id);
 }
None of the generated Queries return the books related to the author. Nor is there a query created to look up all books by an author id. See the generated details page here: ![Details Page](https://user-images.githubusercontent.com/175176/122465657-5b581a80-cf86-11eb-9dda-790849f7583b.png)
Reproduce the error

See this test Project to Reproduce: https://github.com/hepaestus/testproject

Related issues

NO SURE

Suggest a Fix

On thing that would be awesome is if someone who better understands how relationships work in JH would write better documentation on relationship syntax in JDL. Better documentation of how the JDL syntax effects the generated features would be super helpful and probably reduce the number of questions. Right now it is not comprehensive and in various different locations. For example in the JDL examples repo [https://github.com/jhipster/jdl-samples] there are plenty examples however none that are documented. There is no mention of what the syntax is expected to achieve. Or why a particular syntax was used instead of another. This would be super helpful.

JHipster Version(s)

7.0.1

testproject@0.0.1-SNAPSHOT /home/pete/git/testproject/foobar
└── generator-jhipster@7.0.1
JHipster configuration, a .yo-rc.json file generated in the root folder
.yo-rc.json file
{
  "generator-jhipster": {
    "authenticationType": "jwt",
    "cacheProvider": "ehcache",
    "clientFramework": "angularX",
    "serverPort": "8080",
    "serviceDiscoveryType": "eureka",
    "skipUserManagement": false,
    "withAdminUi": true,
    "baseName": "testproject",
    "buildTool": "maven",
    "databaseType": "sql",
    "devDatabaseType": "mysql",
    "enableHibernateCache": true,
    "enableSwaggerCodegen": false,
    "enableTranslation": true,
    "jhiPrefix": "jhi",
    "languages": ["en", "es"],
    "messageBroker": false,
    "prodDatabaseType": "mysql",
    "searchEngine": "elasticsearch",
    "skipClient": false,
    "testFrameworks": [],
    "websocket": false,
    "applicationType": "monolith",
    "blueprints": [],
    "clientPackageManager": "npm",
    "clientTheme": "lumen",
    "clientThemeVariant": "dark",
    "creationTimestamp": 1623354443010,
    "dtoSuffix": "DTO",
    "jhipsterVersion": "7.0.1",
    "jwtSecretKey": "YourJWTSecretKeyWasReplacedByThisMeaninglessTextByTheJHipsterInfoCommandForObviousSecurityReasons",
    "nativeLanguage": "en",
    "otherModules": [],
    "packageName": "com.hepaestus.testproject",
    "packageFolder": "com/hepaestus/testproject",
    "reactive": false,
    "skipServer": false,
    "entitySuffix": "",
    "entities": ["Author", "Book", "Car", "Dog", "Echo", "Friend"],
    "skipCheckLengthOfIdentifier": false,
    "skipFakeData": false,
    "pages": [],
    "lastLiquibaseTimestamp": 1623354803000
  }
}
JDL for the Entity configuration(s) entityName.json files generated in the .jhipster directory
JDL entity definitions
entity Author {
  name String
  firstName String
  lastName String
  type AddressType
}
entity Book {
  name String required
  created LocalDate
  description String
}
entity Car {
  name String required
  title String
  date LocalDate
  type CustomerType
}
entity Dog {
  name String required
  description String
  created LocalDate
}
entity Echo {
  name String required
  description String
  created LocalDate
}
entity Friend {
  name String required
  description String
  created LocalDate
}
enum AddressType {
  DEFAULT,
  HOME,
  BUSINESS
}
enum CustomerType {
  DEFAULT,
  REGULAR,
  ARTIST,
  DESIGNER,
  CORPORATE,
  ADMIN
}

relationship OneToOne {
  // Expecting Bi-Directional BUT this causes an error when saving
  Author{user(login)} to User

  //Expecting Bi-Directional Dog should have an "owner" Does not work as expected
  Author{dog(name)} to Dog{owner(name)}
}
relationship OneToMany {
  // Expecting Author details page to display a SET of books and the Book detail to display the Author
  // This is not what happens. Author does not show their books. But Does show other relationships.
  Author{books} to Book{author(name)}

  // Expecting Author to have a SET of Cars and the Car to have an Owner
  // This is not what happens. Author details does not list Cars. A Car does list and Owner.
  Author{cars} to Car{owner}

  // Expecting Bi-Directional with the name being displayed not the ID
  // This does not work. The dog is listed by in the Car details not not the inverse again.
  Car{dog(name)} to Dog{car(name)}
}
relationship ManyToMany {

  // Expecting Bi-Directional echos should display their Author
  // Echoes have no reference to Authors
  Author{echo} to Echo{author(name)}

  // Expecting Bi-Directional Friend should display their Authors and Authors Details shows Friends
  Author{friends(name)} to Friend{authors(name)}

  // Expecting Bi-Directional Friend should display their Dogs 
  // Friend does not reference dogs in the details page or the API.
  // Dog does reference its Friends in the details page 
  // Friend object does NOT reference Dog 
  Dog{friend} to Friend{dog}
}

dto Author, Book, Car, Dog, Echo, Friend with mapstruct
service Author, Book, Car, Dog, Echo, Friend with serviceClass
search Author, Book, Car, Dog, Echo, Friend with elasticsearch

Here is the Dog Details Page: image Notice it does not Display the Owner

Environment and Tools

openjdk version "11.0.11" 2021-04-20 OpenJDK Runtime Environment (build 11.0.11+9-Ubuntu-0ubuntu2.20.10) OpenJDK 64-Bit Server VM (build 11.0.11+9-Ubuntu-0ubuntu2.20.10, mixed mode, sharing)

git version 2.27.0

node: v14.0.0

npm: 7.16.0

Docker version 20.10.7, build f0df350

docker-compose version 1.29.2, build 5becea4c

Entity configuration(s) entityName.json files generated in the .jhipster directory

AUTHOR ENTITY

Author Entity
{
  "name": "Author",
  "fields": [
    {
      "fieldName": "name",
      "fieldType": "String"
    },
    {
      "fieldName": "firstName",
      "fieldType": "String"
    },
    {
      "fieldName": "lastName",
      "fieldType": "String"
    },
    {
      "fieldName": "type",
      "fieldType": "AddressType",
      "fieldValues": "DEFAULT,HOME,BUSINESS"
    }
  ],
  "relationships": [
    {
      "relationshipType": "one-to-one",
      "otherEntityName": "user",
      "otherEntityRelationshipName": "author",
      "relationshipName": "user",
      "ownerSide": true
    },
    {
      "relationshipType": "one-to-one",
      "otherEntityName": "dog",
      "otherEntityRelationshipName": "author",
      "relationshipName": "dog",
      "ownerSide": true
    },
    {
      "relationshipType": "one-to-many",
      "otherEntityName": "book",
      "otherEntityRelationshipName": "author",
      "relationshipName": "books"
    },
    {
      "relationshipType": "one-to-many",
      "otherEntityName": "car",
      "otherEntityRelationshipName": "owner",
      "relationshipName": "cars"
    },
    {
      "relationshipType": "many-to-many",
      "otherEntityName": "echo",
      "otherEntityRelationshipName": "author",
      "relationshipName": "echo",
      "ownerSide": true
    },
    {
      "relationshipType": "many-to-many",
      "otherEntityName": "friend",
      "otherEntityRelationshipName": "authors",
      "relationshipName": "friends",
      "otherEntityField": "name",
      "ownerSide": true
    }
  ],
  "entityTableName": "author",
  "dto": "mapstruct",
  "pagination": "no",
  "service": "serviceClass",
  "jpaMetamodelFiltering": false,
  "fluentMethods": true,
  "readOnly": false,
  "embedded": false,
  "applications": ["testproject"],
  "searchEngine": "elasticsearch",
  "changelogDate": "20210610194823"
}

BOOK ENTITY

Book Entity
{
  "name": "Book",
  "fields": [
    {
      "fieldName": "name",
      "fieldType": "String",
      "fieldValidateRules": ["required"]
    },
    {
      "fieldName": "created",
      "fieldType": "LocalDate"
    },
    {
      "fieldName": "description",
      "fieldType": "String"
    }
  ],
  "relationships": [
    {
      "relationshipType": "many-to-one",
      "otherEntityName": "author",
      "otherEntityRelationshipName": "books",
      "relationshipName": "author",
      "otherEntityField": "name"
    }
  ],
  "entityTableName": "book",
  "dto": "mapstruct",
  "pagination": "no",
  "service": "serviceClass",
  "jpaMetamodelFiltering": false,
  "fluentMethods": true,
  "readOnly": false,
  "embedded": false,
  "applications": ["testproject"],
  "searchEngine": "elasticsearch",
  "changelogDate": "20210610194923"
}

Car ENTITY

Car Entity
{
  "name": "Car",
  "fields": [
    {
      "fieldName": "name",
      "fieldType": "String",
      "fieldValidateRules": ["required"]
    },
    {
      "fieldName": "title",
      "fieldType": "String"
    },
    {
      "fieldName": "date",
      "fieldType": "LocalDate"
    },
    {
      "fieldName": "type",
      "fieldType": "CustomerType",
      "fieldValues": "DEFAULT,REGULAR,ARTIST,DESIGNER,CORPORATE,ADMIN"
    }
  ],
  "relationships": [
    {
      "relationshipType": "one-to-many",
      "otherEntityName": "dog",
      "otherEntityRelationshipName": "car",
      "relationshipName": "dog",
      "otherEntityField": "name"
    },
    {
      "relationshipType": "many-to-one",
      "otherEntityName": "author",
      "otherEntityRelationshipName": "cars",
      "relationshipName": "owner"
    }
  ],
  "entityTableName": "car",
  "dto": "mapstruct",
  "pagination": "no",
  "service": "serviceClass",
  "jpaMetamodelFiltering": false,
  "fluentMethods": true,
  "readOnly": false,
  "embedded": false,
  "applications": ["testproject"],
  "searchEngine": "elasticsearch",
  "changelogDate": "20210610195023"
}

Dog ENTITY

Dog Entity
{
  "name": "Dog",
  "fields": [
    {
      "fieldName": "name",
      "fieldType": "String",
      "fieldValidateRules": ["required"]
    },
    {
      "fieldName": "description",
      "fieldType": "String"
    },
    {
      "fieldName": "created",
      "fieldType": "LocalDate"
    }
  ],
  "relationships": [
    {
      "relationshipType": "many-to-many",
      "otherEntityName": "friend",
      "otherEntityRelationshipName": "dog",
      "relationshipName": "friend",
      "ownerSide": true
    },
    {
      "relationshipType": "one-to-one",
      "otherEntityName": "author",
      "otherEntityRelationshipName": "dog",
      "relationshipName": "author",
      "ownerSide": false
    },
    {
      "relationshipType": "many-to-one",
      "otherEntityName": "car",
      "otherEntityRelationshipName": "dog",
      "relationshipName": "car",
      "otherEntityField": "name"
    }
  ],
  "entityTableName": "dog",
  "dto": "mapstruct",
  "pagination": "no",
  "service": "serviceClass",
  "jpaMetamodelFiltering": false,
  "fluentMethods": true,
  "readOnly": false,
  "embedded": false,
  "applications": ["testproject"],
  "searchEngine": "elasticsearch",
  "changelogDate": "20210610195123"
}

ECHO ENTITY

Echo Entity
{
  "name": "Echo",
  "fields": [
    {
      "fieldName": "name",
      "fieldType": "String",
      "fieldValidateRules": ["required"]
    },
    {
      "fieldName": "description",
      "fieldType": "String"
    },
    {
      "fieldName": "created",
      "fieldType": "LocalDate"
    }
  ],
  "relationships": [
    {
      "relationshipType": "many-to-many",
      "otherEntityName": "author",
      "otherEntityRelationshipName": "echo",
      "relationshipName": "author",
      "otherEntityField": "name",
      "ownerSide": false
    }
  ],
  "entityTableName": "echo",
  "dto": "mapstruct",
  "pagination": "no",
  "service": "serviceClass",
  "jpaMetamodelFiltering": false,
  "fluentMethods": true,
  "readOnly": false,
  "embedded": false,
  "applications": ["testproject"],
  "searchEngine": "elasticsearch",
  "changelogDate": "20210610195223"
}

FRIEND ENTITY

Friend Entity
{
  "name": "Friend",
  "fields": [
    {
      "fieldName": "name",
      "fieldType": "String",
      "fieldValidateRules": ["required"]
    },
    {
      "fieldName": "description",
      "fieldType": "String"
    },
    {
      "fieldName": "created",
      "fieldType": "LocalDate"
    }
  ],
  "relationships": [
    {
      "relationshipType": "many-to-many",
      "otherEntityName": "dog",
      "otherEntityRelationshipName": "friend",
      "relationshipName": "dog",
      "ownerSide": false
    },
    {
      "relationshipType": "many-to-many",
      "otherEntityName": "author",
      "otherEntityRelationshipName": "friends",
      "relationshipName": "authors",
      "otherEntityField": "name",
      "ownerSide": false
    }
  ],
  "entityTableName": "friend",
  "dto": "mapstruct",
  "pagination": "no",
  "service": "serviceClass",
  "jpaMetamodelFiltering": false,
  "fluentMethods": true,
  "readOnly": false,
  "embedded": false,
  "applications": ["testproject"],
  "searchEngine": "elasticsearch",
  "changelogDate": "20210610195323"
}
Browsers and Operating System

Chrome Browser Linux version 5.8.0-53-generic (buildd@lgw01-amd64-020) (gcc (Ubuntu 10.2.0-13ubuntu1) 10.2.0, GNU ld (GNU Binutils for Ubuntu) 2.35.1) #60-Ubuntu SMP Thu May 6 07:46:32 UTC 2021

github-actions[bot] commented 3 years ago

This issue is stale because it has been open 30 days with no activity. Our core developers tend to be more verbose on denying. If there is no negative comment, possibly this feature will be accepted. We are accepting PRs :smiley:. Comment or this will be closed in 7 days

github-actions[bot] commented 10 months ago

This issue is stale because it has been open for too long without any activity. Due to the moving nature of jhipster generated application, bugs can become invalid. If this issue still applies please comment otherwise it will be closed in 7 days