yahoo / elide

Elide is a Java library that lets you stand up a GraphQL/JSON-API web service with minimal effort.
https://elide.io
Other
1k stars 229 forks source link

SpringBoot Implementation @MAnyToMany wrong result #466

Open francescoesposito7 opened 7 years ago

francescoesposito7 commented 7 years ago

Hi everyone, i'm discovering your framework and i'm trying to do a simple spring boot project to understand Elide's basics. Here my project:

https://github.com/francescoesposito7/elideTest

I've this problem:

When i try lo list all my entities at the URL /{entity}, the first element always have one element in his relationship, but if i try to use the url /{entity}/id, i find all the objects connected.

Here the result at the URL: /parent

{
    "data": [
        {
            "type": "parent",
            "id": "15",
            "attributes": {
                "description": null,
                "name": "Giorgio"
            },
            "relationships": {
                "children": {
                    "data": [
                        {
                            "type": "child",
                            "id": "22"
                        }
                    ]
                }
            }
        },
        {
            "type": "parent",
            "id": "16",
            "attributes": {
                "description": null,
                "name": "Frank"
            },
            "relationships": {
                "children": {
                    "data": [
                        {
                            "type": "child",
                            "id": "24"
                        }
                    ]
                }
            }
        }
    ]
}

Here at the URL: /parent/15

{
    "data": {
        "type": "parent",
        "id": "15",
        "attributes": {
            "description": null,
            "name": "Giorgio"
        },
        "relationships": {
            "children": {
                "data": [
                    {
                        "type": "child",
                        "id": "22"
                    },
                    {
                        "type": "child",
                        "id": "23"
                    }
                ]
            }
        }
    }
}

It's my fault? what's wrong with my procedure?

Thanks a lot for any answer. Big Up!

DennisMcWherter commented 7 years ago

I haven't been able to fully investigate this yet, but my intuition tells me this may be an issue with how your @ManyToMany is interacting with hibernate. Usually you need to specify a @JoinColumn or @JoinTable to make this work. Here is one such example.

In any case, I will try to pull down and investigate your test further and see if I can come up with a solution when I have a chance.

francescoesposito7 commented 7 years ago

First of all thank you for your answer.

I've already used the@JoinTableannotation, but same result.

The strange thing is that the problem is always on the first element of the json.

If i have n_parents with m_childs, after the first element, i've the right result. For this reason i've open this issue.

Thanks a lot, i continue by my side the investigation.

IDragonfire commented 7 years ago

The last weekend I also fough with a @ManyToMany relation (https://github.com/FAForever/faf-java-api/pull/91) If I have time today I will check your example project, because for me @ManyToMany worked like expected ...

PS.: Did you read this wiki? https://en.wikibooks.org/wiki/Java_Persistence/ManyToMany

IDragonfire commented 7 years ago

@francescoesposito7 You defined no @JoinTable like @DeathByTape mention. How should the Persistence Layer find the relation from Parent to Child?

francescoesposito7 commented 7 years ago

@IDragonfire I defined the @JoinTable but i didn't commit on github.

However, the problem is always there for me, because the persistence level finds all the relationship from "Parent" to "Chid" except for the first element

IDragonfire commented 7 years ago

@francescoesposito7 It finds the relationship on this code? https://github.com/francescoesposito7/elideTest/blob/671d079da7f42471e87dfa33a01a4703c877ddcb/ElideTest/src/main/java/com/elide/test/entities/Parent.java#L45

We cannot check your @JoinTable definition if you don't commit it ....

francescoesposito7 commented 7 years ago

Commint done in this moment sorry! @IDragonfire

IDragonfire commented 7 years ago

@francescoesposito7 Please take a look at the documentation, e.g. https://en.wikibooks.org/wiki/Java_Persistence/ManyToMany @JoinColumn's are missing. How should the persistence layer know what columns in the table are related to what entities?

francescoesposito7 commented 7 years ago

@IDragonfire As you suggest, i've modified my @JoinTable annotation like this

    @ManyToMany(fetch = FetchType.EAGER)
    @JsonManagedReference
    @JoinTable(
            name = "parents_childs",
            joinColumns =@JoinColumn(name="ParentID",referencedColumnName = "id"),
            inverseJoinColumns=@JoinColumn(name="Child_ID", referencedColumnName="id"))
    public List<Child> getChildren() {
        return this.children;
    }

Here the result with /parent:

{
    "data": [
        {
            "type": "parent",
            "id": "1",
            "attributes": {
                "description": null,
                "name": "Giorgio"
            },
            "relationships": {
                "children": {
                    "data": [
                        {
                            "type": "child",
                            "id": "1"
                        }
                    ]
                }
            }
        },
        {
            "type": "parent",
            "id": "2",
            "attributes": {
                "description": null,
                "name": "Frank"
            },
            "relationships": {
                "children": {
                    "data": [
                        {
                            "type": "child",
                            "id": "3"
                        }
                    ]
                }
            }
        }
    ]
}

Here the result with /parent/1:

{
    "data": {
        "type": "parent",
        "id": "1",
        "attributes": {
            "description": null,
            "name": "Giorgio"
        },
        "relationships": {
            "children": {
                "data": [
                    {
                        "type": "child",
                        "id": "1"
                    },
                    {
                        "type": "child",
                        "id": "2"
                    }
                ]
            }
        }
    }
}

Always the same issue...Anyway i continue to not understand why the persistence layer doesn't work only on the First element!!!

IDragonfire commented 7 years ago

Next time please format the message ;)

Request: /parent

{  
   "data":[  
      {  
         "type":"parent",
         "id":"1",
         "attributes":{  
            "description":null,
            "name":"Giorgio"
         },
         "relationships":{  
            "children":{  
               "data":[  
                  {  
                     "type":"child",
                     "id":"1"
                  }
               ]
            }
         }
      },
      {  
         "type":"parent",
         "id":"2",
         "attributes":{  
            "description":null,
            "name":"Frank"
         },
         "relationships":{  
            "children":{  
               "data":[  
                  {  
                     "type":"child",
                     "id":"3"
                  }
               ]
            }
         }
      }
   ]
}

Request: /parent/1

{  
   "data":{  
      "type":"parent",
      "id":"1",
      "attributes":{  
         "description":null,
         "name":"Giorgio"
      },
      "relationships":{  
         "children":{  
            "data":[  
               {  
                  "type":"child",
                  "id":"1"
               },
               {  
                  "type":"child",
                  "id":"2"
               }
            ]
         }
      }
   }
}

Code: https://github.com/francescoesposito7/elideTest/blob/d0b48d1ff33bb9b85d5f659b55aa985e476c06a3/ElideTest/src/main/java/com/elide/test/entities/Parent.java

Now the issue is more readable ;) @francescoesposito7 Did you try to remove @JsonManagedReference? Your behaviour is really strange ...

Elide-Version: 3.0.4 https://github.com/francescoesposito7/elideTest/blob/d0b48d1ff33bb9b85d5f659b55aa985e476c06a3/ElideTest/pom.xml#L58

francescoesposito7 commented 7 years ago

@francescoesposito7 Did you try to remove @JsonManagedReference? Your behaviour is really strange ...

Yes always the same...

IDragonfire commented 7 years ago

I am sorry @francescoesposito7 , I cannot reproduce your error. I copied your files to my sample project (using h2 in memory instead of postgres) https://github.com/IDragonfire/spring-boot-jpa-elide/tree/test/francescoesposito7 Are the entities in the database or do you create it at runtime? Without the complete app it is hard to say what went wrong ....

Check the example project to see the diferents.

Warning: My example project is dirty and should not be considered as copy source^^

francescoesposito7 commented 7 years ago

@IDragonfire Thanks a lot!

IDragonfire commented 7 years ago

@francescoesposito7 If you solved the issue, please write the solution here and close the issue ;)

francescoesposito7 commented 7 years ago

@IDragonfire of course ;)

Drag0nSlayer commented 7 years ago

Hi @IDragonfire

I downloaded your test project with @ManytoMany. And it worked for me too but only in parent side if you create another parent and assignate it to an existing child. If you navigate to /child/, the child has only one parent.

I think the bug is only present if you have an annotation @Eager in the concerned side but @Lazy seems to fix that.

francescoesposito7 commented 7 years ago

Hi @Drag0nSlayer ,

like you say when i change my @ManyToMany(fetch = FetchType.EAGER) to @ManyToMany(fetch = FetchType.LAZY) it works!!!

Thanks a lot!!! BIG UP!!

At the moment i think that there is a little bug if the fetchMode is EAGER both sides, like in my project.

IDragonfire commented 7 years ago

@francescoesposito7 what bug? Is this issue solved?

francescoesposito7 commented 7 years ago

@francescoesposito7 what bug? Is this issue solved?

This issue is solved if, we don't consider when in boths entity side there is a fetch type EAGER.

Otherwise if i have LAZY fetch both sides or LAZY in one model and EAGER in the other model, the problem is solved.

I've tried also Katharsis and, doesn't matter the fetch type, the serialization is correct, for this reason i think there's a bug.

In fact, in your branch test cloned from my project @IDragonfire you have changed in one model the fetch type from EAGER to LAZY.

https://github.com/IDragonfire/spring-boot-jpa-elide/blob/test/francescoesposito7/src/main/java/com/matthewcasperson/elidetest/jpa/Parent.java#L52

but in my project:

https://github.com/francescoesposito7/elideTest/blob/master/ElideTest/src/main/java/com/elide/test/entities/Parent.java#L45

I suppose for this reason that there is a little bug, but it's only a thinking.