Generator-jhipster: ManyToMany relationship generates wrong relationship table name

Created on 20 Dec 2019  ·  33Comments  ·  Source: jhipster/generator-jhipster

Overview of the issue

I use JDL file

entity Material {
    name String
}
entity MaterialOrigin {
    name String
}
relationship ManyToMany {
    Material{origin} to MaterialOrigin{material}
}
This wrongly generates relationship table name as "material_origin" instead of "material_origin_material" in files: * `.../domain/Material.java` * `.../changelog/..._added_entity_constraints_Material.xml` * `.../changelog/..._added_entity_Material.xml` The issue reveals itself on `./mvnw` with the error
WARN 26590 --- [  restartedMain] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is java.lang.RuntimeException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'servletEndpointRegistrar' defined in class path resource [org/springframework/boot/actuate/autoconfigure/endpoint/web/ServletEndpointManagementContextConfiguration$WebMvcServletEndpointManagementContextConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar]: Factory method 'servletEndpointRegistrar' threw exception; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'auditEventsEndpoint' defined in class path resource [org/springframework/boot/actuate/autoconfigure/audit/AuditEventsEndpointAutoConfiguration.class]: Unsatisfied dependency expressed through method 'auditEventsEndpoint' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'customAuditEventRepository' defined in file [.../target/classes/com/company/app/repository/CustomAuditEventRepository.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'persistenceAuditEventRepository': Cannot create inner bean '(inner bean)#1c95bc62' of type [org.springframework.orm.jpa.SharedEntityManagerCreator] while setting bean property 'entityManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#1c95bc62': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.MappingException: Foreign key (FKipo7e0wsvsnrag9hoy1hnmeb6:material_origin [origin_id])) must have same number of columns as the referenced primary key (material_origin [material_id,origin_id])
##### **Motivation for or Use Case** The app fails to run without a proper relation table. The `material_origin_material` is not even described anywhere despite being referenced from `.../changelog/..._added_entity_MaterialOrigin.xml`. ##### **Reproduce the error** 1. Initialize fresh app with `jhipster` and all the defaults (just hit enter like 10 times) 2. Save the JDL above to the `jhipster-many-to-many-bug.jdl` 3. Bootstrap models with `jhipster import-jdl ./jhipster-many-to-many-bug.jdl --force` 4. `./mvnw` ##### **Related issues** I didn't find any. ##### **Suggest a Fix** ##### **JHipster Version(s)** 6.5.1 ##### **JHipster configuration** INFO! Using JHipster version installed locally in current project's node_modules INFO! Executing jhipster:info INFO! Options: from-cli: true ##### **JHipster Version(s)**
[email protected] /home/nikolay.seliverstov/Projects/jh-manytomany-bug
└── [email protected] 

##### **JHipster configuration, a `.yo-rc.json` file generated in the root folder**
.yo-rc.json file
{
  "generator-jhipster": {
    "promptValues": {
      "packageName": "com.janssen.fsra",
      "nativeLanguage": "en"
    },
    "jhipsterVersion": "6.5.1",
    "applicationType": "monolith",
    "baseName": "jhipster",
    "packageName": "com.janssen.fsra",
    "packageFolder": "com/janssen/fsra",
    "serverPort": "8080",
    "authenticationType": "jwt",
    "cacheProvider": "ehcache",
    "enableHibernateCache": true,
    "websocket": false,
    "databaseType": "sql",
    "devDatabaseType": "h2Disk",
    "prodDatabaseType": "mysql",
    "searchEngine": false,
    "messageBroker": false,
    "serviceDiscoveryType": false,
    "buildTool": "maven",
    "enableSwaggerCodegen": false,
    "jwtSecretKey": "bXktc2VjcmV0LXRva2VuLXRvLWNoYW5nZS1pbi1wcm9kdWN0aW9uLWFuZC10by1rZWVwLWluLWEtc2VjdXJlLXBsYWNl",
    "embeddableLaunchScript": false,
    "useSass": true,
    "clientPackageManager": "npm",
    "clientFramework": "angularX",
    "clientTheme": "none",
    "clientThemeVariant": "",
    "testFrameworks": [],
    "jhiPrefix": "jhi",
    "entitySuffix": "",
    "dtoSuffix": "DTO",
    "otherModules": [],
    "enableTranslation": true,
    "nativeLanguage": "en",
    "languages": ["en"],
    "blueprints": []
  }
}

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


JDL entity definitions

entity Material {
  name String
}
entity MaterialOrigin {
  name String
}
relationship ManyToMany {
  Material{origin} to MaterialOrigin{material}
}

Environment and Tools

openjdk version "11.0.5" 2019-10-15
OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.5+10)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.5+10, mixed mode)

git version 2.17.1

node: v8.15.1

npm: 6.4.1

yeoman: 3.1.1

Docker version 19.03.5, build 633a0ea838

docker-compose version 1.23.2, build 1110ad01

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


Material.json

{
    "name": "Material",
    "fields": [
        {
            "fieldName": "name",
            "fieldType": "String"
        }
    ],
    "relationships": [
        {
            "relationshipType": "many-to-many",
            "otherEntityName": "materialOrigin",
            "otherEntityRelationshipName": "material",
            "relationshipName": "origin",
            "otherEntityField": "id",
            "ownerSide": true
        }
    ],
    "changelogDate": "20191220115447",
    "entityTableName": "material",
    "dto": "no",
    "pagination": "no",
    "service": "no",
    "jpaMetamodelFiltering": false,
    "fluentMethods": true,
    "readOnly": false,
    "clientRootFolder": "",
    "applications": "*"
}


MaterialOrigin.json

{
    "name": "MaterialOrigin",
    "fields": [
        {
            "fieldName": "name",
            "fieldType": "String"
        }
    ],
    "relationships": [
        {
            "relationshipType": "many-to-many",
            "otherEntityName": "material",
            "otherEntityRelationshipName": "origin",
            "relationshipName": "material",
            "otherEntityField": "id",
            "ownerSide": false
        }
    ],
    "changelogDate": "20191220115448",
    "entityTableName": "material_origin",
    "dto": "no",
    "pagination": "no",
    "service": "no",
    "jpaMetamodelFiltering": false,
    "fluentMethods": true,
    "readOnly": false,
    "clientRootFolder": "",
    "applications": "*"
}

Browsers and Operating System

Ubuntu 18.04
Firefox 71

  • [x] Checking this box is mandatory (this is just to show you read everything)
area relationships v7

All 33 comments

The second issue is that the FK descriptions for the relationship keys are being created twice:

  1. In the entity_constraints_Material
  2. In the entity_constraints_MaterialOrigin

I referenced this bug on a commit by mistake.

Hm. I can try to follow the https://github.com/jhipster/jhipster-core/issues/404#issuecomment-566462309 but do not think that can help with the issue. Let me check.

You can try these steps

  1. Create a fresh folder
  2. Create file jhipster-many-to-many-bug.jdl inside the folder with the contents

    jhipster-many-to-many-bug.jdl
application {
  config {
    databaseType sql
    devDatabaseType h2Disk
    enableHibernateCache true
    enableSwaggerCodegen false
    enableTranslation true
    jhiPrefix jhi
    languages [en]
    messageBroker false
    nativeLanguage en
    packageName com.acme
    //packageFolder "com/acme"
    prodDatabaseType mysql
    searchEngine false
    serviceDiscoveryType false
    skipClient false
    skipServer false
    testFrameworks []
    websocket false
    jhipsterVersion "6.5.1"
    applicationType monolith
    baseName jhipster
    serverPort 8080
    authenticationType jwt
    cacheProvider ehcache
    buildTool maven
    //jwtSecretKey MGNhZjk2ZTFlYTU0YmQ0NWU0MTYxMWVjZjBiMGI1YzE1N2Q1YzFkN2M5M2EwODcxNWM5OTI4NTFhMGY4NDdkMTkzNmZmN2Q1MTljZWE4N2U3MmFjNDQ5NzZlNmRkYjcyNGRjMWUxMTQ1NWYwNGIxMWQ2OWUyODY2MTI4ZmQxMmM=
    //embeddableLaunchScript false
    useSass true
    clientPackageManager npm
    clientFramework angularX
    clientTheme none
    clientThemeVariant
    entitySuffix
    dtoSuffix DTO
    //otherModules []
    //blueprints []
    skipUserManagement false
  }

  entities Material, MaterialOrigin
}

entity Material {
  name String
}
entity MaterialOrigin {
  name String
}
relationship ManyToMany {
  Material{origin} to MaterialOrigin{material}
}

  1. Run jhipster import-jdl jhipster-many-to-many-bug.jdl

And you still can observe the bug above. So it's not related to the config conflicts (jhipster/jhipster-core#404).

I'm moving it to JCore. And I don't think it's related to the 404.

I've tried generating the entities/relationship with the CLI, the only difference I've got between the generated JSON is in MaterialOrigin.json, is the "otherEntityField": "id" attribute that shouldn't be here.
Apart from that, the generation is the same...

Well, the issue is not about difference between cli and something else. The issue that I have entity that generates the table material_origin plus the framework tries to generate the many to many relationship table with the same name. Which is obviously wrong.

In the JDL, you have the option to specify the table name.
Like that

entity MyEntity(my_table_name)

Currently I see two workarounds. One is to rename the material_origin table to something like MaterialOrigin(material_origin_name). The second one is to change the owner of the relationship. But that's usually not desirable. Personally I go by simply fixing the generated files

The issue that I have my own table material_origin and the framework tries to generate the many to many relationship table with the same name. Which is obviously wrong.

Do you mean that you had an existing table in your DB and you used JHipster on top of the same schema?

No, I'm not. The entity Material Origin generates table with the name material_origin and the many to many relationship generates a table with the exact same name. The compilation is ok but these explode in runtime.

Moving it back to the generator, it's a deeper issue than just JDL generation.

Should we rename the issue to express that?

Currently I see two workarounds. One is to rename the material_origin table to something like MaterialOrigin(material_origin_name). The second one is to change the owner of the relationship. But that's usually not desirable. Personally I go by simply fixing the generated files

Which files needs to be fixed?

Please see the list of the affected files in the issue description. If you are asking about list of jhipster source files then I cannot help here. I didn't dive into the issue that deep.

https://github.com/jhipster/generator-jhipster/blob/c1d1f4c036fbe0a5a8d88929e58e57ead53876ef/generators/generator-base.js#L1357-L1358

You can fix by changing the relationship name.

To fix this issue on generator we have 2 options:

  • Calculate every generated table name and add a conflict algorithm (Append _xx)
  • Add a different separator for join tables. Ex 2 _ instead of 1.

http://dev.mysql.com/doc/refman/5.5/en/identifiers.html
https://www.postgresql.org/docs/8.0/sql-syntax.html#SQL-SYNTAX-IDENTIFIERS
https://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements008.htm

I would go with ability to change the resulting relationship table name. But I guess this is too hard since JDL syntax lacks the feature.

I guess jhipster just messed up some variables in the templates. Since there is ../changelog/..._added_entity_constraints_MateriaOriginl.xml that refers the correct relationship table name (material_origin_material). The problem that the table being created with a different name (material_origin).

If you are not using any blueprint, you can try the following:

npm install generator-jhipster-customizer
jhipster import-jdl many-to-many-bug.jdl --blueprints customizer --customizers relationship_separator
jhipster import-jdl many-to-many-bug.jdl --blueprints customizer --customizers relationship_separator

You have to rerun the command after first error.

Let me know if it fixes the problem.

@mshima I'm sorry, but why do we need a separate generator in order to fix the bug?

Is it possible to detect name clashing beforehand and generate an alternative relationship table name in case of clashing like <rel_name1>_<rel_name2> -> <rel_name1>_<rel_name2>_rel ?

But I guess the collision finding is out of the scope that's why the current solution is like that.

@mshima I'm sorry, but why do we need a separate generator in order to fix the bug?
No, it's just a workaround.

The bug is triaged.
The fix is simple.
The patch is ready.
But it's a breaking change when regenerating.

JHipster Developers don't agree that we should create a config to workaround this.
https://github.com/jhipster/generator-jhipster/pull/11030#discussion_r362032865

Is it possible to detect name clashing beforehand and generate an alternative relationship table name in case of clashing like <rel_name1>_<rel_name2> -> <rel_name1>_<rel_name2>_rel ?

Adding prefix of suffix, will not fix relations like
relation_name -> other = relation_name_other
rel -> name_other = relation_name_other

I think we should add prefix rel_ to tables.
It will be easier to differentiate between other tables, but is not needed to fix this.

But I guess the collision finding is out of the scope that's why the current solution is like that.

Yes, too hard.

Should implement this?
Change relationships table name with:

  • rel_ prefix?
  • __ (double underscore) separator?

To be honest I would use $tablename1_$tablename2 instead of the current $tablename1_$reffieldname.

rel_ sounds good to me

@pascalgrimaud with our current entities adding a rel_ prefix and __ separator tests do not pass.
Only pass with 1 character prefix.

To be honest I would use $tablename1_$tablename2 instead of the current $tablename1_$reffieldname.

Then you would have conflict when creating 2 relationships with same entity.

with our current entities adding a rel_ prefix and __ separator tests do not pass. Only pass with 1 character prefix.

Do you understand why ?
So what do you suggest for this @mshima ?

@pascalgrimaud table name conflicts due to trimming.
Could be fixed by renaming some entities.

IMO change separator only.
r_ prefix would be nice, not sure about _ prefix.

another idea would be to generate a hash, using the name of entities: rel_hash
so with this solution, we can regenerate entities without changing the name of relationships

what do you think ?

@pascalgrimaud I like the idea of hashing.
But more like rel_ prefix, __ separator, _xxx 3 char hash suffix.
I think it’s important to keep entity name for db maintenance.

keeping entity name is important for db maintenance, you're right, and 3 char hash suffix would be enough to avoid conflict

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pascalgrimaud picture pascalgrimaud  ·  4Comments

SudharakaP picture SudharakaP  ·  3Comments

pascalgrimaud picture pascalgrimaud  ·  3Comments

trajakovic picture trajakovic  ·  4Comments

marcelinobadin picture marcelinobadin  ·  3Comments