views:

875

answers:

1

Still duking it out with Hibernate...

I'm using Hibernate-Annotations instead of hbm.xml files for my beans, but I'm currently running into a problem where the SQL that Hibernate is generating references nonexistent database columns.

For instance, here is the code:

Query q = session.createQuery("FROM Status ORDER BY post_date DESC");

(it is retrieving a list of Status objects, ordered from most recent to least recent, and each Status object contains its own list of Comment objects...yes, think Facebook posts)

And here is the query it generates:

Hibernate: select status0_.pid as pid1_, status0_.content as content1_, status0_.owner_uid as owner5_1_, status0_.parent_pid as parent6_1_, status0_.post_date as post4_1_, status0_.type as type1_ from POSTS status0_ order by post_date DESC limit ?

The problem is, within that query, it references status0_.owner_uid and status0_.parent_pid, but those fields do not exist in the database. When I change the query manually to use status0_.owner and status0_.parent, respectively, and feed it to MySQL, it works perfectly.

There are four classes involved.

A User, which has no concept of anything else in the system (relevant fields below):

@Entity
@Embeddable
@Table(name="USERS")
public class User {

    @Id
    @GeneratedValue
    @Column(name="uid")
    private Integer uid;

...
}

A Post, an abstract superclass for Comment and Status that are stored in the same table and differentiated via a column type (relevant fields below):

@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
    name="type", 
    discriminatorType=DiscriminatorType.STRING
) 
@MappedSuperclass
@Entity
@Embeddable
@Table(name="POSTS")
public abstract class Post {

    @Id
    @GeneratedValue
    @Column(name="pid")
    private Integer pid;

    @ManyToOne
    @Embedded
    private Post parent;

    @ManyToOne
    @Embedded
    private User owner;

    @Column(name="post_date")
    private Timestamp postDate;

    @Column(name="content")
    private String content;

    @Column(name="type", updatable=false)
    private String type;
    ...
}

A Status class, subclassing Post; sets parent to null and also contains a list of Comments (relevant fields below):

@Entity
@Table(name="POSTS")
@DiscriminatorValue("status")
public class Status extends Post {

    @OneToMany(mappedBy="parent")
    @OrderBy("postDate asc")
    private List<Comment> children; 
    ...
}

A Comment class, subclassing Post; has a non-null parent (entire class posted below):

@Entity
@DiscriminatorValue("comment")
@Table(name="shannonq_posts")
public class Comment extends Post {
    // this class is literally empty
}

In summary: I have no idea why Hibernate is appending the embedded class' IDs into the query, resulting in a non-existent column. Ideally I would have liked to have added the @Column(name="parent") annotation to these fields, but it seems that Hibernate doesn't allow this particular annotation to fields labeled with @ManyToOne.

Any help is appreciated! Thank you!

Edit: FYI, if I manually change the columns in my database to match what Hibernate is generating, I get another error: Cannot instantiate abstract class or interface: Post. Obviously my configuration is incorrect. :P

+1  A: 

Hibernate's default naming strategy for ManyToOne associations takes your field name and appends PK column of the associated table using underscore.

Thus for Post (superclass of Status) you get owner_uid and parent_pid as column names because uid and pid are respective PK column names.

You can override this by using @JoinColumn annotation:

@ManyToOne
@JoinColumn(name = "parent")
private Post parent;

@ManyToOne
@JoinColumn(name = "owner")
private User owner;

or by implementing your own NamingStrategy (Hibernate-specific and not recommended for beginners :-) )

On a side note, @Embedded signifies that you want to map given entity as component (basically, part of this same table). Putting @ManyToOne and @Embedded on the same property is (or should be) illegal.

ChssPly76
I should just start messaging you when I have a Hibernate question :) Problem fixed! Thank you again!
Magsol
No worries, that's why I hang out in the Hibernate tag :-)
ChssPly76