self mapping one to many hibernate spring boot - java

MYSQL Schema:
CREATE TABLE `nodes` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`node_id` int(11) DEFAULT NULL,
`name` varchar(255) NOT NULL,
`type` int(255),
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `node_id_self_to_id` (`node_id`),
KEY `type_foreign_to_node_types` (`type`),
CONSTRAINT `node_id_self_to_id` FOREIGN KEY (`node_id`) REFERENCES `nodes` (`id`),
CONSTRAINT `type_foreign_to_node_types` FOREIGN KEY (`type`) REFERENCES `node_types` (`id`)
)
MY Entity Class:
#Entity
#Table(name = "nodes")
public class Nodes {
#Id
#JoinColumn(name = "node_id")
private int id;
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name="node_id")
private Nodes nodeId;
#OneToMany(mappedBy="nodeId")
private Set<Nodes> mynodeIds = new HashSet<Nodes>();
private String name;
private Date created_at;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "type")
private Nodetypes nodetypes;
#OneToMany(mappedBy = "nodes", cascade = CascadeType.ALL)
private Set<Nodeattributes> nodeattributes;
#OneToMany(mappedBy = "nodes", cascade = CascadeType.ALL)
private Set<Products> products;
public Nodetypes getNodetypes() {
return nodetypes;
}
public void setNodetypes(Nodetypes nodetypes) {
this.nodetypes = nodetypes;
}
public Set<Products> getProducts() {
return products;
}
public void setProducts(Set<Products> products) {
this.products = products;
}
public Set<Nodeattributes> getNodeattributes() {
return nodeattributes;
}
public void setNodeattributes(Set<Nodeattributes> nodeattributes) {
this.nodeattributes = nodeattributes;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getCreated_at() {
return created_at;
}
public void setCreated_at(Date created_at) {
this.created_at = created_at;
}
}
and In the Junit test,
public void testCreateNodes() {
Nodes node1 = new Nodes();
node1.setId(2222);
node1.setCreated_at(new java.util.Date());
node1.setName("nodeName");
node1.setNodetypes(nodetypesRepository.findById(1111).get());
nodesRepository.save(node1);
}
I'm using Spring Boot Project. How to do a self mapping of One To Many in Hibernate. So, How can I Implement hibernate self join annotations one to many? Any help would be appreciated. I have followed this blog to develop the project, but still getting null value in my MYSQL.
https://viralpatel.net/blogs/hibernate-self-join-annotations-one-to-many-mapping/

Related

How do I map/create an entity class for a table which has only foreign keys in Spring Boot

I have the following tables in my database (Postgres): questions, responses and question_response.
There is a many to many relationships between questions and responses tables and I have created the entity classes for both of these relations. I now have to create an entity mapping for question_respone table which doesn't have any primary key.
I have read about using #IdClass or #EmbeddedId, however, I am not sure how do I map two foreign keys which are primary keys in two different classes using these annotations.
Note:
updating the entities after implementing the changes mentioned in the comments
Thanks!
questions.sql
CREATE TABLE questions(
id BIGSERIAL PRIMARY KEY,
question VARCHAR(255)
);
respones.sql
CREATE TABLE responses(
id BIGSERIAL PRIMARY KEY,
response VARCHAR(255)
);
question_respone.sql #
CREATE TABLE question_response(
question_id bigint REFERENCES questions ON DELETE CASCADE,
response_id bigint REFERENCES responses ON DELETE CASCADE,
PRIMARY KEY ( question_id, response_id)
);
Question.java
#Entity
#Table(name = "questions")
public class Question{
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="qid_seq")
#SequenceGenerator(name = "qid_seq", sequenceName="questions_id_seq")
#Column(name = "id")
private Long id;
#Column(name = "questionText")
private String questionText;
#OneToMany(mappedBy = "question", cascade = CascadeType.ALL, orphanRemoval = true)
private List<QuestionResponse> responses;
public Question() {}
public Question(String questionText) {
super();
this.questionText = questionText;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getQuestionText() {
return questionText;
}
public void setQuestionText(String questionText) {
this.questionText = questionText;
}
public List<QuestionResponse> getResponses() {
return responses;
}
}
QuestionResponse.java
#Entity
#Table(name = "question_response")
public class QuestionResponse {
#Id
#ManyToOne
private Question question;
#Id
#ManyToOne
private Response response;
public QuestionResponse() {
super();
}
public QuestionResponse(Question question, Response response) {
super();
this.question= question;
this.response = response;
}
public Question getQuestion() {
return question;
}
public void setQuestion(Question question) {
this.question = question;
}
public Response getResponse() {
return response;
}
public void setResponse(Response response) {
this.response = response;
}
}
Response.java
#Entity
#Table(name = "responses")
public class Response {
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="rid_seq")
#SequenceGenerator(name = "rid_seq", sequenceName="questions_id_seq")
#Column(name = "id")
private Long id;
#Column(name = "responseText")
private String responseText;
#OneToMany(mappedBy = "response", cascade = CascadeType.ALL, orphanRemoval = true)
private List<QuestionResponse> question;
public Response() {}
public Response(String responseText) {
super();
this.responseText = responseText;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getResponseText() {
return responseText;
}
public void setResponseText(String responseText) {
this.responseText = responseText;
}
public List<QuestionResponse> getQuestion() {
return question;
}
}
# WildFly console #
13:54:49,581 ERROR [org.springframework.boot.SpringApplication] (ServerService Thread Pool -- 86) Application run failed: 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.AnnotationException:
No identifier specified for entity: com.poc.questionnarie.QuestionResponse
You can break up the many-to-many relationship into a one-to-many-to-one construct as described here:
https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#associations-many-to-many-bidirectional-with-link-entity

How to map objects dynamically in hibernate

I need help on hibernate mapping for a bean property refers to multiple classes.
In my application we are implementing permissions. These permission are not specific to certain user it may based on groups(contains list of users) and roles. So, Permissions will apply to users, roles and groups.
Following are ddl and entity classes. Please review and help me.
DDL:
--stores the application users
CREATE TABLE users (
id serial PRIMARY KEY,
name text,
CONSTRAINT uk_users_name UNIQUE (name)
);
--stores the application groups
CREATE TABLE groups (
id serial PRIMARY KEY,
name text,
CONSTRAINT uk_groups_name UNIQUE (name)
);
--stores the application roles
CREATE TABLE roles (
id serial PRIMARY KEY,
name text,
CONSTRAINT uk_roles_name UNIQUE (name)
);
--stores the application object types
CREATE TABLE app_object_types (
id serial PRIMARY KEY,
name text,
CONSTRAINT uk_app_object_types_name UNIQUE (name)
);
INSERT INTO app_object_types (name) VALUES ('USERS');
INSERT INTO app_object_types (name) VALUES ('GROUPS');
INSERT INTO app_object_types (name) VALUES ('ROLES');
CREATE TABLE app_permissions (
id serial PRIMARY KEY,
object_type_id integer REFERENCES app_object_types(id), -- To represent the object type
object_id integer, -- Objecct_id refers users -> id, groups -> id, roles - id
permission_name text,
CONSTRAINT uk_permissions UNIQUE (object_type_id, object_id, permission_name)
);
Entity Classes:
#Entity
#Table(name = "users")
public class Users {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private int name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getName() {
return name;
}
public void setName(int name) {
this.name = name;
}
}
#Entity
#Table(name = "groups")
public class Groups {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private int name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getName() {
return name;
}
public void setName(int name) {
this.name = name;
}
}
#Entity
#Table(name = "roles")
public class Roles {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private int name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getName() {
return name;
}
public void setName(int name) {
this.name = name;
}
}
#Entity
#Table(name = "app_object_types")
public class AppObjectTypes {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private int name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getName() {
return name;
}
public void setName(int name) {
this.name = name;
}
}
#Entity
#Table(name = "app_permissions")
public class AppPermissions {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#ManyToOne
private String permissionName;
#ManyToOne
private AppObjectTypes appObjectTypes;
private int objectId;
private Class<?> dependentObject;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getPermissionName() {
return permissionName;
}
public void setPermissionName(String permissionName) {
this.permissionName = permissionName;
}
public AppObjectTypes getAppObjectTypes() {
return appObjectTypes;
}
public void setAppObjectTypes(AppObjectTypes appObjectTypes) {
this.appObjectTypes = appObjectTypes;
}
public int getObjectId() {
return objectId;
}
public void setObjectId(int objectId) {
this.objectId = objectId;
}
public Class<?> getDependentObject() {
return dependentObject;
}
public void setDependentObject(Class<?> dependentObject) {
this.dependentObject = dependentObject;
}
}
I want to map user (or) group (or) role bean object to AppPermissions -> dependentObject using hibernate. I don't know it is possible or not please help me.
I would suggest you consider the use of #Inheritance here on your AppPermission entity in order to specialize each subclass based on the dependent object types.
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name = "OBJECT_TYPE")
public class AppPermission {
#Id
#GeneratedValue
private Long permissionId;
private String name;
#Column(name = "OBJECT_TYPE", insertable = false, updatable = false)
private String objectType;
}
#Entity
#DiscriminatorValue("USER")
public class UserAppPermission extends AppPermission {
#ManyToOne(optional = false)
private User user;
}
#Entity
#DiscriminatorValue("ROLE")
public class RoleAppPermission extends AppPermission {
#ManyToOne(optional = false)
private Role role;
}
#Entity
#DiscriminatorValue("GROUP")
public class GroupAppPermission extends AppPermission {
#ManyToOne(optional = false)
private Group group;
}
The first difference here with these mappings from yours is that your AppPermission table will be constructed differently from your current schema and would look like the following (note 4 tables):
Table: AppPermission
id NOT NULL IDENTITY(1,1)
name VARCHAR(255)
OBJECT_TYPE VARCHAR(31)
Table: UserAppPermission
id NOT NULL BIGINT (FK -> AppPermission)
user_id NOT NULL BIGINT (FK -> User)
Table: RoleAppPermission
id NOT NULL BIGINT (FK -> AppPermission)
role_id NOT NULL BIGINT (FK -> Role)
Table: GroupAppPermission
id NOT NULL BIGINT (FK -> AppPermission)
group_id NOT NULL BIGINT (FK -> Group)
The whole point of a database is to help us maintain referential integrity. That's why when a table depends on a row from another table, the dependent table rows that relate to the row you wish to remove should be removed first to avoid constraint violations. This is precisely why I have split the relations into separate tables and here I've defined each relation as "optional=false" so that basically it represents a join-table.
Another additional benefit is that if your AppPermission has attributes you need to store specific to the type of dependent object, you can freely add those attributes to the subclass and those attributes are stored separately in that specific subclass's table.
This setup also eliminates your AppObjectType table because that is now driven as part of Hibernate's discriminator pattern. Be aware that if you have other "object-types" you'll need to introduce their specific implementations too with this setup.
Lastly, I exposed (which you don't have to) the OBJECT_TYPE as an non-insertable and non-updatable field because Hibernate manages that for you. But I've exposed it allowing you to make polymorphic queries and determine the object type of the resulting object without having to perform instanceof checks if you wish.

Hibernate Cannot add or update a child row: a foreign key constraint fails

When I'm trying to save object into database I got error:
java.sql.SQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`smartphones`.`smartphone`, CONSTRAINT `fk_smartphone_resolution1` FOREIGN KEY (`resolution_id`) REFERENCES `resolution` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION)
First thing is I have wrong name of references column in Smartphone class but I checked and it looks well. Maybe someone figure out what is the reason of this issue?
Short database screenshot
SQL script to create smartphone table
CREATE TABLE IF NOT EXISTS `smartphones`.`smartphone` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(45) NULL DEFAULT NULL,
`resolution_id` INT(11) NOT NULL,
...other
PRIMARY KEY (`id`, `resolution_id`),
UNIQUE INDEX `id_UNIQUE` (`id` ASC),
INDEX `fk_smartphone_resolution1_idx` (`resolution_id` ASC),
CONSTRAINT `fk_smartphone_resolution1`
FOREIGN KEY (`resolution_id`)
REFERENCES `smartphones`.`resolution` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
Smartphone class but with one relationship object.
package com.project.model;
import javax.persistence.*;
#Entity
public class Smartphone {
private int id;
private String name;
private Resolution resolutionId;
#Id
#Column(name = "id")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Basic
#Column(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#ManyToOne(fetch=FetchType.EAGER, cascade=CascadeType.PERSIST)
#JoinColumn(name = "resolution_id", referencedColumnName = "id", nullable = false)
public Resolution getResolutionId() {
return resolutionId;
}
public void setResolutionId(Resolution resolutionId) {
this.resolutionId = resolutionId;
}
}
[Edit: Parsing smartphone model and saving into database]
#RequestMapping(value = { "apple" }, method = RequestMethod.GET)
public String parseApple(ModelMap model) {
try {
String appleData = Utilities.getResourceAsString(this, "json/apple.json");
JSONArray array = new JSONArray(appleData);
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
for (int i = 0; i < array.length(); i++) {
Smartphone smartphone = new Smartphone();
String resolutionValue = array.getJSONObject(i).getString("resolution");
String resolution_w = resolutionValue.split(" ")[0];
String resolution_h = resolutionValue.split(" ")[2];
Resolution resolution = new Resolution();
resolution.setHeight(Integer.valueOf(resolution_h));
resolution.setWidth(Integer.valueOf(resolution_w));
resolution.setTypeId(typeService.findByCode(session, Resolution.serialId));
session.save(resolution);
smartphone.setResolutionId(resolution);
//other
session.save(smartphone);
break;
}
transaction.commit();
sessionFactory.close();
} catch (IOException e) {
e.printStackTrace();
}
return "index";
}
[Edit: Added] Resolution class:
#Entity
public class Resolution {
public static final int serialId = 106;
private int id;
private Integer height;
private Integer width;
private Type typeId;
private Collection<Smartphone> resolutionId;
#Id
#Column(name = "id")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Basic
#Column(name = "height")
public Integer getHeight() {
return height;
}
public void setHeight(Integer height) {
this.height = height;
}
#Basic
#Column(name = "width")
public Integer getWidth() {
return width;
}
public void setWidth(Integer width) {
this.width = width;
}
#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name = "type_id", referencedColumnName = "id", nullable = false)
public Type getTypeId() {
return typeId;
}
public void setTypeId(Type typeId) {
this.typeId = typeId;
}
#LazyCollection(LazyCollectionOption.FALSE)
#OneToMany(mappedBy = "resolutionId")
public Collection<Smartphone> getResolutionId() {
return resolutionId;
}
public void setResolutionId(Collection<Smartphone> resolutionId) {
this.resolutionId = resolutionId;
}
}
Almost well. You have to add above getId() method for Resolution class and similar code below. Probably your resolution object has always 0 as id after save method call.
#Column(name = "id", unique = true, nullable = false)
#GeneratedValue(strategy = GenerationType.AUTO)
You're trying to add/update a row to resolution that does not have a valid value for the id field based on the values stored in smartphone.
You must first insert the row to your resolution table.
Add
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Annotations in Model class.

Select from two table from hibernate?

I have two tables in db employee and department as:
CREATE TABLE test.employee (
EMPID int(10) unsigned NOT NULL DEFAULT '1',
Name varchar(45) NOT NULL DEFAULT '1',
DEPTID int(10) unsigned NOT NULL DEFAULT '1',
PRIMARY KEY (EMPID),
KEY FK_employee_1 (DEPTID),
CONSTRAINT FK_employee_1 FOREIGN KEY (DEPTID) REFERENCES department (DEPTID)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE test.department (
DEPTID int(10) unsigned NOT NULL AUTO_INCREMENT,
Name varchar(45) NOT NULL,
PRIMARY KEY (DEPTID)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
And my mapping classes are as below:
Employee2.java
#Entity
#Table(name="EMPLOYEE")
public class Employee2 {
#Id #GeneratedValue
#Column(name="EMPID")
private String ID;
#Column(name="Name")
private String Name;
#Column(name="DEPTID")
private String DepartmentID;
public Employee2(String iD, String name, String departmentID){
ID = iD;
Name = name;
DepartmentID = departmentID;
}
public Employee2(){
}
public String getID() {
return ID;
}
public void setID(String iD) {
ID = iD;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public String getDepartmentID() {
return DepartmentID;
}
public void setDepartmentID(String departmentID) {
DepartmentID = departmentID;
}
#OneToOne
#JoinColumn(table = "DEPARTMENT", name = "DEPTID", referencedColumnName="DEPTID")
private Department2 ec;
public Department2 getEc() {
return ec;
}
public void setEc(Department2 ec) {
this.ec = ec;
}
}
Department2.java
#Entity
#Table(name="DEPARTMENT")
public class Department2 {
#Id #GeneratedValue
#Column(name="DEPTID")
private String ID;
#Column(name="Name")
private String Name;
public Department2(String iD, String name) {
ID = iD;
Name = name;
}
public Department2(){
}
public String getID() {
return ID;
}
public void setID(String iD) {
ID = iD;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
}
I want to select from two tables with join as EMPLOYEE.DEPTID = DEPARTMENT.DEPTID
I dont want to write query.
Here is how I m doing it in test class
tx = session.beginTransaction();
Criteria criteria = session.createCriteria(Employee2.class, "employee").
createCriteria("employee.ec", JoinType.INNER_JOIN);
List<Equipment2> rows = criteria.list();
System.out.println(rows.size());
tx.commit();
But I m getting following exception
Failed to create sessionFactory object.org.hibernate.AnnotationException: Cannot find the expected secondary table: no DEPARTMENT available for com.cts.sm.Employee2
Exception in thread "main" java.lang.ExceptionInInitializerError
I m using Hibernate 4.2
Can you please help me as what I m missing in this.
As suggested by #jpprade
Make the following change
#ManyToOne
#JoinColumn(name ="DEPTID", updatable = false, insertable = false)
private Department2 ec;
//getter setter
Thanks
N G

#ManyToOne mapping doesn't work with joined inheritance

I have the following database structure:
CREATE TABLE `author` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`email` varchar(255) NOT NULL,
`password` varchar(255) NOT NULL,
PRIMARY KEY (`id`));
CREATE TABLE `message` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(500) NOT NULL,
`text` varchar(50000) NOT NULL,
`author_id` int(10) unsigned DEFAULT NULL,
`creation_date` datetime NOT NULL,
`last_update_date` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `author_id_fk` (`author_id`),
CONSTRAINT `message_ibfk_1` FOREIGN KEY (`author_id`) REFERENCES `author` (`id`));
CREATE TABLE `comment` (
`id` int(10) unsigned NOT NULL,
`post_id` int(10) unsigned NOT NULL,
KEY `message_id_fk` (`id`),
KEY `post_id_fk` (`post_id`),
CONSTRAINT `comment_ibfk_1` FOREIGN KEY (`id`) REFERENCES `message` (`id`),
CONSTRAINT `comment_ibfk_2` FOREIGN KEY (`post_id`) REFERENCES `post` (`id`));
CREATE TABLE `post` (
`id` int(10) unsigned NOT NULL,
KEY `message_id_fk` (`id`),
CONSTRAINT `post_ibfk_1` FOREIGN KEY (`id`) REFERENCES `message` (`id`) ON DELETE CASCADE);
And the following mapping with hibernate(3.5.4-Final):
#Entity
#Table(name = "author")
public class Author {
private Long id = 0L;
private String name;
private String email;
private String password;
private Set<Post> posts;
private Set<Comment> comments;
#Id
#Column(name = "id")
#GeneratedValue
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Column(name = "email")
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
#Column(name = "password")
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
#OneToMany(mappedBy = "author")
public Set<Post> getPosts() {
return posts;
}
public void setPosts(Set<Post> posts) {
this.posts = posts;
}
#OneToMany(mappedBy = "author")
public Set<Comment> getComments() {
return comments;
}
public void setComments(Set<Comment> comments) {
this.comments = comments;
}
}
#MappedSuperclass
#Table(name = "message")
#Inheritance(strategy = InheritanceType.JOINED)
public abstract class Message implements Serializable {
private Long id;
private String title;
private String text;
private Author author;
private Date creationDate;
private Date lastUpdateDate;
#Id
#Column(name = "id")
#GeneratedValue
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name = "title")
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
#Column(name = "text")
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
#ManyToOne
#JoinColumn(name = "author_id")
public Author getAuthor() {
return author;
}
public void setAuthor(Author author) {
this.author = author;
}
#Column(name = "creation_date")
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}
#Column(name = "last_update_date")
public Date getLastUpdateDate() {
return lastUpdateDate;
}
public void setLastUpdateDate(Date lastUpdateDate) {
this.lastUpdateDate = lastUpdateDate;
}
}
#Entity
#Table(name = "comment")
#PrimaryKeyJoinColumn(name="id")
public class Comment extends Message {
private static final long serialVersionUID = 1L;
private Post post;
#ManyToOne
#JoinColumn(name = "post_id")
public Post getPost() {
return post;
}
public void setPost(Post post) {
this.post = post;
}
}
#Entity
#Table(name = "post")
#PrimaryKeyJoinColumn(name="id")
public class Post extends Message {
private static final long serialVersionUID = 1L;
private Set<Comment> comments;
#OneToMany(mappedBy = "post")
public Set<Comment> getComments() {
return comments;
}
public void setComments(Set<Comment> comments) {
this.comments = comments;
}
}
The main idea is that Comment and Post are inherited from Message and I would like both of them to have bidirectional relation. But when I run the following code:
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
Transaction tx = session.beginTransaction();
Author author = new Author();
author.setName("mike");
author.setPassword("123");
author.setEmail("mike#gmail.com");
Post post = new Post();
post.setAuthor(author);
post.setCreationDate(new Date());
post.setLastUpdateDate(new Date());
post.setText("Text");
post.setTitle("Title");
Long authorId = (Long)session.save(author);
Long postId = (Long)session.save(post);
tx.commit();
I get the following error:
ERROR JDBCExceptionReporter:101 - Unknown column 'author_id' in 'field list'
Exception in thread "main" org.hibernate.exception.SQLGrammarException: could not insert: [org.blogsample.mappingbeans.Post]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:92)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:64)
Update
As #JB Nizet mentioned before I changed #MappedSuperclass to #Entity, after that I've got another error mappedBy reference an unknown target entity property: org.blogsample.mappingbeans.Comment.author, this was solved by changing db structure(removed author_id from message table, added it to each of comment, post and created foreign keys for this column) and moving author(and getter/setter with mapping) to Comment, Post classes.
Your Message class shouldn't be annotated with #MappedSuperclass, but with #Entity. #MappedSuperclass means that entities extending this class inherit columns and associations from the super class, but these columns and associations go in the table of the subclass. author_id is not in the comment table or in the post table. It's in the message table.
Moreover #Table can only be used with an entity. Not with a mapped superclass, which is only used to inherit fields and associations, but is not mapped to its own table like an entity is.
I think your issue here is exactly the same as the one highlighted in this question.
Have a look at my answer there to see if that helps.

Categories