Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

ManyToOne cannot resolved associated instances #189

Closed
eld0 opened this Issue · 25 comments

3 participants

@eld0

HI All,
I've found a problem with ManyToOne relation in Kundera (I'm using Cassandra). The main reason is that an associated instance succesfully persists into database but when I try to fetch it it always null. I investigated records in DB and found that child object always sets a "link" to himself instead of setting link to parent , thats why it couldn't be resolved from DB.
So, I've checkout Kundera sources and found the place where links are set and found something like an issue. After code modifications ManyToOne works properly and child has a right link in cassandra.
Here is an annotation examples from my code:

@Entity
@Table(name = "tokens", schema = "myapp@myapp_pu")
@XmlRootElement(name = "Token")
public class Token
{
    @Id
    @Column(name = "token_id")
    private String id;
    @ManyToOne(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
    @JoinColumn(name = "client_id")
    private Client client;
.....
}

@Entity
@Table(name = "clients", schema = "myapp@myapp_pu")
@XmlRootElement(name = "Client")
public class Client
{
    @Id
    @Column(name = "client_id")
    private String id;
    @Column(name = "client_name")
    private String clientName;
}

And here is the code changed by me. (I can make a patch if you wish)

com.impetus.kundera.persistence.PersistenceDelegator
if (parents != null && !parents.isEmpty())
{
    for (NodeLink parentNodeLink : parents.keySet())
    {
        if (!parentNodeLink.getMultiplicity().equals(ForeignKey.MANY_TO_MANY))
            parentNodeLink.addLinkProperty(LinkProperty.LINK_VALUE, node.getEntityId());
    }
}

if (children != null && !children.isEmpty())
{
    for (Entry<NodeLink,Node> childNodeLinkEntry : children.entrySet())
    {
        NodeLink childNodeLink = childNodeLinkEntry.getKey();
        Node childNode = childNodeLinkEntry.getValue();
        if (!childNodeLink.getMultiplicity().equals(ForeignKey.MANY_TO_MANY))
            childNodeLink.addLinkProperty(LinkProperty.LINK_VALUE, childNode.getEntityId());
    }
}
previously it was (I got sources from 2.3.1)
if (parents != null && !parents.isEmpty())
{
    for (NodeLink parentNodeLink : parents.keySet())
    {
        if (!parentNodeLink.getMultiplicity().equals(ForeignKey.MANY_TO_MANY))
            parentNodeLink.addLinkProperty(LinkProperty.LINK_VALUE, node.getEntityId());
    }
}

if (children != null && !children.isEmpty())
{
    for (NodeLink childNodeLink : children.keySet())
    {
        if (!childNodeLink.getMultiplicity().equals(ForeignKey.MANY_TO_MANY))
            childNodeLink.addLinkProperty(LinkProperty.LINK_VALUE, node.getEntityId());
    }
}

Could you please help me? Is this an issue or I'm making something wrong?

@mevivs
Collaborator

KK,
Can you please look into this?

IT is same as :
https://github.com/impetus-opensource/Kundera/blob/trunk/kundera-tests/src/test/java/com/impetus/kundera/tests/crossdatastore/useraddress/MTOUniAssociationTest.java

If it is an issue, then @eld0 might need to raise a patch for this.
Thanks @eld0 for pointing this issue.

-Vivek

@mevivs
Collaborator

Possible to share CRUD code snippet?

@mevivs mevivs referenced this issue from a commit
@mevivs mevivs Fix for issue #189 b74f83e
@mevivs
Collaborator

This has been fixed in current trunk branch. Issue was data population was incorrect in case owning side of assication is not having any other column exception associated one.
A test case is added, please refer above mentioned commit revision number.

-Vivek

@mevivs mevivs was assigned
@roqs23

Is this similar to this error for kundera-mongo as well?

java.lang.NullPointerException
at com.impetus.kundera.query.KunderaQuery.initEntityClass(KunderaQuery.java:358)
at com.impetus.kundera.query.KunderaQuery.postParsingInit(KunderaQuery.java:333)
at com.impetus.kundera.query.QueryResolver.getQueryImplementation(QueryResolver.java:75)
at com.impetus.kundera.persistence.PersistenceDelegator.createQuery(PersistenceDelegator.java:576)
at com.impetus.kundera.persistence.EntityManagerImpl.createNamedQuery(EntityManagerImpl.java:485)

@mevivs
Collaborator

I guess, this is different. It must be something to do with invalid query syntax. As per above exception trace looks like query syntax is not correct and "From" keyword is missing from query. However, we are adding more validation around this.

-Vivek

@roqs23

I'm glad you're already working on improving the validations. The entities and query was working when I used hibernate. The query is "select e from ErrorMessages e where e.languages.languageCode= :langCode and e.errorCode= :errorCode".

@mevivs
Collaborator

Please share your entity definition(s).

@roqs23

/**

  • ErrorMessages generated by hbm2java
    */
    @Entity
    @Table(name = "ERROR_MESSAGES")
    @NamedQueries({
    @NamedQuery(name=ErrorMessages.FETCH_BY_LANG_ERRCODE,
    query="select e from ErrorMessages e where e.languages.languageCode= :langCode and e.errorCode= :errorCode " )
    })
    public class ErrorMessages implements java.io.Serializable {
    public final static String FETCH_BY_LANG_ERRCODE = "ErrorMessages.FETCH_BY_LANG_ERRCODE";

    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "error_id", unique = true, nullable = false)
    private Integer errorId;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "lang_id", nullable = false)
    private Languages languages;

    @Column(name = "error_code", nullable = false, length = 20)
    private String errorCode;

    @Column(name = "error_message", nullable = false, length = 1000)
    private String errorMessage;

    public ErrorMessages() {
    }

    public ErrorMessages(Languages languages, String errorCode,
    String errorMessage) {
    this.languages = languages;
    this.errorCode = errorCode;
    this.errorMessage = errorMessage;
    }

    public Integer getErrorId() {
    return this.errorId;
    }

    public void setErrorId(Integer errorId) {
    this.errorId = errorId;
    }

    public Languages getLanguages() {
    return this.languages;
    }

    public void setLanguages(Languages languages) {
    this.languages = languages;
    }

    public String getErrorCode() {
    return this.errorCode;
    }

    public void setErrorCode(String errorCode) {
    this.errorCode = errorCode;
    }

    public String getErrorMessage() {
    return this.errorMessage;
    }

    public void setErrorMessage(String errorMessage) {
    this.errorMessage = errorMessage;
    }

}
//-----------------------------------------------
/**

  • Languages generated by hbm2java
    */
    @Entity
    @Table(name = "LANGUAGES")
    @NamedQueries({
    @NamedQuery(name=Languages.FETCH_ALL,
    query="select L from Languages L" )
    ,@NamedQuery(name=Languages.FETCH_BY_CODE,
    query="select L from Languages L where L.languageCode = :languageCode" )
    })
    public class Languages implements java.io.Serializable {
    public final static String FETCH_ALL = "Languages.FETCH_ALL";
    public final static String FETCH_BY_CODE = "Languages.FETCH_BY_CODE";

    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "lang_id", unique = true, nullable = false)
    private Integer langId;

    @Column(name = "language", length = 100)
    private String language;

    @Column(name = "language_code", length = 100)
    private String languageCode;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "languages")
    private Set errorMessageses = new HashSet(0);

    public Languages() {
    }

    public Languages(String language, String languageCode) {
    this.language = language;
    this.languageCode = languageCode;
    }

    @JsonIgnore
    public Integer getLangId() {
    return this.langId;
    }

    public void setLangId(Integer langId) {
    this.langId = langId;
    }

    @JsonProperty("lang")
    public String getLanguage() {
    return this.language;
    }

    public void setLanguage(String language) {
    this.language = language;
    }

    @JsonProperty("code")
    public String getLanguageCode() {
    return this.languageCode;
    }

    public void setLanguageCode(String languageCode) {
    this.languageCode = languageCode;
    }

    @JsonIgnore
    public Set getErrorMessageses() {
    return this.errorMessageses;
    }

    public void setErrorMessageses(Set errorMessageses) {
    this.errorMessageses = errorMessageses;
    }

}

@mevivs
Collaborator

In case "e.languages.languageCode", if languages is a reference to associated entity, then such queries will not work and not currently supported by Kundera. However if you query over Owning entity's field, it will work.

-Vivek

@mevivs
Collaborator

Also your entity definition is not correct and you need to add schema attribute to @Table annotation. Have a look at:
https://github.com/impetus-opensource/Kundera/blob/trunk/kundera-mongo/src/test/java/com/impetus/client/crud/PersonMongo.java

for reference.

@eld0

Thanks alot for fix! Works as expected all my tests are green :)
But I have another issue with bidirectional associations on Cassandra.
So, when I'll add :

@OneToMany(mappedBy = "client", fetch = FetchType.LAZY)
private Set<Token> tokens;

to Tokens class, collection will always null. (there are related records in DB)
Is this an issue? (I'll raise a new ticket if needed)

@mevivs
Collaborator

Can you please share your CRUD code snippet? As it is working fine for me if i add

    @OneToMany(mappedBy = "client", fetch = FetchType.LAZY)
    private Set<Token> tokens;

it is returning as expected

@mevivs
Collaborator

This is what i have tried with existing test case.

     query="Select t from TokenClient t";
        q = em.createQuery(query);
        List<TokenClient> resultClient = q.getResultList();
        Assert.assertNotNull(resultClient);
        Assert.assertEquals(1, resultClient.size());
        Assert.assertEquals(2,resultClient.get(0).getTokens().size());

Please see, if we are in line with this.

@eld0

Hi,
Looks like your patch didn't resolve an issue with @ManyToOne relation. My bad, I was run unit tests on database with correctly persisted relations (that were persisted with my patch). I made a short example test which failed on my environment. It's succesfully persists into DB (with wrong link to client) and when I try to fetch it it always null.
How I can attach my project to this ticket? (It says that only images supported)

And I'm using Cassandra 1.2. Maybe it will help...

@mevivs
Collaborator

Drop box link should be fine?

-Vivek

@eld0

Hi,
Any news? Are you checked my example code?

@mevivs
Collaborator

Hi,
Yes. i am looking into it. Will get back to you by today.

-Vivek

@mevivs
Collaborator

Hi,
Changes suggested by you is a partial fix and will update you on this with proper fix.

-Vivek

@eld0

Thanks for your quick response, I'll wait for updates.

@mevivs mevivs referenced this issue from a commit
@mevivs mevivs Fix Added for issue #189 553ae80
@mevivs
Collaborator

I have added a fix for this. Please verify it should be fine now.

-Vivek

@eld0

Works like a charm. Thanks!
(bidirectional associations are working too)
Thanks a lot for your quick fix! I'm very appreciate this.

@mevivs
Collaborator

Great. Just to share one more fix is added and in case trouble in future you may take an update.
2.4(releasing in next 2-3 days) should work for you for all such unwanted issues!

Cheers,
-Vivek

@mevivs
Collaborator

Are we good to close on this?

-Vivek

@eld0

yes, thanks!

@mevivs mevivs closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.