Hibernate could not determine type - java

I'm stuck with this error :
org.hibernate.MappingException: Could not determine type for: com.mywebsite.entity.Image, at table: User, for columns: [org.hibernate.mapping.Column(profilePhoto)]
I know it have been asked a lot but i'm stuck with this. It have been trying for hours and I can't find anything that work ...
Here are my 2 classes :
#Entity
public class Image extends com.mywebsite.entity.Entity{
//System
#Id
#GeneratedValue
private int id;
[...]
}
#Entity
public class User extends com.mywebsite.entity.Entity{
//System
#Id
#GeneratedValue
private int id;
[...]
//Data
private Image profilePhoto;
[...]
}
Can someone help me there ?

EDIT:
Try this:
#ManyToOne
#JoinColumn(name="profilephoto_id", foreignKey = #ForeignKey(name = "put_name_here_If_You_HaveAForeignKeyConstraint"))
private Image profilePhoto;
ORIGINAL:
From the docs:
Every non static non transient property (field or method depending on the access type) of an entity is considered persistent, unless you annotate it as #Transient.
So Hibernate thinks that field is from the database, and it's trying to find that column in your table. Either that column does not exist and it should, in which case you should have an annotation mapping for it like #Column; or it doesn't exist on the database and it shouldn't exist, in which case you should use #Transient like the documentation suggests.

Related

Java Spring Hibernate JPA PostgreSQL Avoid saving duplicate rows / records

I'm very green when it comes to databases. I feel like this is probably a pretty common database problem, I can't seem to find the correct search terms to find my answer.
My issue is "duplicate" rows in a table. I'm trying to save restaurant food menus in a database, and for the most part its working alright. I have a object called RestaurantWeek, which contains a list of RestaurantDay objects and each day contains a list of RestaurantCourse objects. They get saved as such in the database: image. "weeks_days" and "days_courses" tables are the link between the "weeks", "days" and "courses" tables.
Now the problem comes when many days can have the same "course". Almost every single day has "Salad" as a course, so what ends up happening is I have 12 identical rows in my "courses" table, the only exception being the id column: image. So now the question is, how can I tell JPA or Hibernate to use the existing "Salad" row in my "courses" table instead of inserting a new one every time? Is it possible to do this by adding some specific annotation to my objects or their properties?
I have tried setting the "name" property on "RestaurantCourse" to unique with #Column(unique=true) but then I get errors about hibernate trying to save multiple courses with the same name (since name must be unique). I have tried grabbing the "courses" table when saving data and using the same id multiple times, but then I get errors about hibernate trying to save multiple courses with the same id (since id must be unique).
Is it even possible to fix this "easily", such as with few specific annotation I'm in the unknown about? Do I need to change something else about how my data is saved to the database, such as the classes, the annotations, or the way I'm trying to save?
Here are my classes.
#AllArgsConstructor
#NoArgsConstructor
#Data
#Entity
#Table(name="weeks")
public class RestaurantWeek {
#Id
private long id;
private Date saveDate;
private String weekName;
#OneToMany(cascade = CascadeType.ALL)
private List<RestaurantDay> days;
}
#AllArgsConstructor
#NoArgsConstructor
#Data
#Entity
#Table(name="days")
public class RestaurantDay {
#Id
#GeneratedValue (strategy = GenerationType.IDENTITY)
private Long id;
private String day;
#OneToMany(cascade = CascadeType.ALL)
private List<RestaurantCourse> courses;
}
#AllArgsConstructor
#NoArgsConstructor
#Data
#TypeDef(name = "list-array", typeClass = ListArrayType.class)
#Entity
#Table(name = "courses")
public class RestaurantCourse {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(unique = true)
private String name;
private String price;
private String type;
#Type(type = "list-array")
#Column(name = "tags", columnDefinition = "text[]")
private List<String> tags;
}
And what I'm using to save:
#Repository
public interface RestaurantMenuRepository extends JpaRepository<RestaurantWeek, Long> {
}
public class RestaurantMenuServiceImpl implements RestaurantMenuService {
#Autowired
private RestaurantMenuRepository restaurantMenuRepository;
#Override
public RestaurantWeek addNewWeek(RestaurantWeek restaurantWeek) {
return this.restaurantMenuRepository.save(restaurantWeek);
}
}
Thanks in advance.
Yes is posible, you must use existing entity. But use in this method
public RestaurantWeek addNewWeek(RestaurantWeek restaurantWeek) parameter RestaurantWeek is not correct try put this method some dto class with need field to create entity class, additionally pass the parameter to available identify courses entity find which you can doing relationship and add to days entity.
No pass all parameter every time!
Alright, finally found the correct search terms and found the answer. Resolution was a combination of serob's answer and a bunch of googling.
In RestaurantDay I changed #OneToMany to #ManyToMany.
I created repository interfaces for RestaurantDay and RestaurantCourse.
When saving the course, I save the courses first, then the days, and finally the week, while grabbing all the new ids.
public RestaurantWeek addNewWeek(RestaurantWeek restaurantWeek) {
for (RestaurantDay day : restaurantWeek.getDays()) {
for (RestaurantCourse course : day.getCourses()) {
RestaurantCourse dbCourse = this.restaurantCourseRepository.findCourseByName(course.getName());
if (dbCourse == null) {
course.setId(this.restaurantCourseRepository.save(course).getId());
}
else {
course.setId(dbCourse.getId());
}
}
this.restaurantDayRepository.save(day);
}
return this.restaurantMenuRepository.saveAndFlush(restaurantWeek);
}
Try #NaturalId, this would make your name an Id for the Course entity:
https://vladmihalcea.com/the-best-way-to-map-a-naturalid-business-key-with-jpa-and-hibernate/

spring-data-jdbc error Required identifier property not found for class

Getting below error while loading data from database
java.lang.IllegalStateException: Required identifier property not found for class com.sudhirt.practice.springdatajdbcpractice.entity.AuthorRef!
at org.springframework.data.mapping.PersistentEntity.getRequiredIdProperty(PersistentEntity.java:105)
at org.springframework.data.jdbc.core.EntityRowMapper.readEntityFrom(EntityRowMapper.java:143)
at org.springframework.data.jdbc.core.EntityRowMapper.readFrom(EntityRowMapper.java:124)
at org.springframework.data.jdbc.core.EntityRowMapper.lambda$createInstance$0(EntityRowMapper.java:167)
Below is the entity class AuthorRef
#Data
#Table("BOOK_AUTHOR")
#NoArgsConstructor
#AllArgsConstructor
public class AuthorRef {
private Long author;
}
What might be the reason for above error?
Source code is available at https://github.com/sudhirtumati/spring-data-jdbc-sample
You are referencing AuthorRef in a Set inside your aggregate root Book.
public class Book {
#Id
private Long id;
private String name;
// ...
private Set<AuthorRef> authorRefList;
// ...
}
Without an id column Spring Data can't determine a primary key for AuthorRef.
Just adding an #Id annotation to author should be sufficient.
Alternatively you could use a List which will add an additional book_key column which together with the book column form a primary key.

How to use hibernate to query for an object with a nested object that has a nested collection of objects

Using Hibernate, I need to query a MySQL database for a Post entity that has a one-to-one relationship with a Poll entity that has a one-to-many relationship with an Answer entity. I need the Post object to contain the Poll object and its Poll object to contain its Answer objects. Here's the basic class setup:
Update:
The Post table must not have a primary key column. It is a waste of data. I need to be able to get Post objects from the database using the user_id column. Getting Post objects using the user_id column is the only way it will ever be done, so it makes no sense for me to have a primary key column. So if you're going to provide an answer that provides insight into a solution that solves my problem, please keep those specifications in mind.
Post Class:
#Entity
#Table(name="user_feed")
public class Post implements Serializable {
//id for the user that is meant to receive the post
//*post object is taken from a table that will contain
//*posts for many different users
#Id
#Column(name="user_id")
private long mUserId;
//poll id
#Id
#Column(name="poll_id")
private long mPollId;
//boolean that indicates whether this post is a repost
#Column(name="is_repost")
private boolean mIsRepost;
//date the post was created
#Column(name="date_created")
private Date mDateCreated;
//the poll this post contains
#OneToOne
#JoinColumn(name="poll_id")
private Poll mPoll;
Poll Class:
#Entity
#Table(name="poll")
public class Poll implements Serializable{
//the poll's id
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id")
private long mId;
//id of the user who created the poll
#Column(name="user_id")
private long mUserId;
//the text of the poll's question
#Column(name="question")
private String mQuestion;
//the date the poll was created
#Column(name="date_created")
private Date mDateCreated;
//the answer objects for this poll
#OneToMany
#JoinColumn(name="id")
private List<Answer> mAnswers;
Answer Class:
#Entity
#Table(name="answer")
public class Answer implements Serializable {
//id for a particular answer
//*this is not a necessary value for the application logic, but
//*Hibernate forces me to designate an #Id annotation for every
//*entity, so I created this field and the associated column in
//*the database
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id")
private long mId;
//the answer's text
#Column(name="answer_text")
private String mAnswer;
//the id of the poll to which this answer pertains to
#Column(name="poll_id")
private long mPollId;
***I'm confused about the id for this table. It doesn't make sense for each answer to have a primary key, but Hibernate requires some sort of #Id annotation in the class, so I decided to just create a primary key column in the table for the sake of Hibernate. It's never used. I would like to get rid of it, but there really isn't anything that makes one Answer unique from another for the same poll except for their text at the moment -- it's not necessary for the application logic.
Query I came up with: doesn't work
.
This query was really just me testing to see if I could get a single Post object with all of its nested objects. I knew if I could get one, getting a collection wouldn't be much more of a stretch -- but I can't even get one.
Session session = HibernateUtilities.openSession();
session.beginTransaction();
//29 is a post meant for a particular user and 47 is the id of the
//poll that should be contained in the post
Post post = (Post)session.get(Post.class, new Post(29, 47));
session.getTransaction().commit();
session.close();
//suppose to return the post in JSON format to a client, but it
//doesn't work when I create the one-to-many relationship between
//the poll and it's answers. It only works without the relationship;
//which I've defined in the Poll class
return mGson.toJson(post);
You shouldn't put the primary keys of the relationships as fields of their own (e.g. you don't need both Post.mPoll and Post.mPollId, just use Post.mPoll.getId() if you need it). If I were to address your problem I would by default (we can discuss Post not having an id later) use the following object model (getters omitted for brevity but I would have them on all fields).
#Entity
public class Post {
#Id
#GeneratedValue
private long id;
#OneToOne
private Poll poll;
}
#Entity
public class Poll {
#Id
#GeneratedValue
private long id;
#OneToMany
private List<Answer> answers;
}
#Entity
public class Answer {
#Id
#GeneratedValue
private long id;
}
Start from there and see where it falls apart. If you want an entity to not have any ID then you can use the #Embedded, #Embeddable, and #ElementCollection annotations.
#Embeddable was originally meant for embedding "value" objects (e.g. things like currency, dates, postal addresses, etc.) and as such these objects do not need a primary key and are completely owned by their owning entity.
You reference the embeddable object with the #Embedded annotation (e.g. your User would have an #Embedded reference to the #Embeddable post if it were a one-to-one).
To reference a collection of embeddable objects you use the #ElementCollection annotation. However, members of an #ElementCollection are immutable (can't modify them in the database, have to remove it from the collection and add a new instance) and cannot be lazily loaded. Given the complexity of your Post object I would not personally make it an embedded class (you may want the ability to edit a post someday?) but if you want to it should work.
I say should because I have never had an embeddedable class that references other non-embeddable entities (e.g. your reference to the Poll). Give those things a try and if they don't work then please post exactly what is going wrong.
Solved it myself. All the comments in the below code designate the changes I made to the code I presented in the question and explain why I made them.
Post Class:
#Entity
#Table(name="user_feed")
public class Post implements Serializable {
#Id
#Column(name="user_id")
private long mUserId;
//removed long mPollId
//hibernate is capable of getting the foreign key for a post's
//poll_id column from its poll object -- mPoll
//so i don't have to have a separate field for the id of this post's
//poll
#Column(name="is_repost")
private boolean mIsRepost;
#Column(name="date_created")
private Date mDateCreated;
//made this field part of the composite id instead of long mPollId
//pretty much the same composite key as before just had to alter
//my implementation of Post.equals(Object) to use this poll's id
//instead of this class's mPollId field
//implementing your own .equals(Object) method is necessary when
//creating composite keys as i do with multiple #Id annotations
//i think you also have to implement your own .hashCode() method too
//but the word hash scares me, so I didn't do it
//the code works, so i'm just gonna let it rock
#OneToOne
#JoinColumn(name="poll_id")
private Poll mPoll;
Poll Class:
#Entity
#Table(name="poll")
public class Poll implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id")
private long mId;
#Column(name="user_id")
private long mUserId;
#Column(name="question")
private String mQuestion;
#Column(name="date_created")
private Date mDateCreated;
//removed #JoinColumn -- not completely sure about why it wasn't
//helping, but many of the examples similar to my use case didn't
//use it so I got rid of it
//added mappedBy variable -- still not really sure what it does
//but it works
//and added FetchType.EAGER so everytime a Poll object is loaded
//the answers it's associated with are loaded too
#OneToMany(mappedBy="mPoll", fetch=FetchType.EAGER)
#Cascade({CascadeType.SAVE_UPDATE, CascadeType.REMOVE})
private List<Answer> mAnswers;
Answer Class:
#Entity
#Table(name="answer")
public class Answer implements Serializable {
//turns out having a primary key on the answer table is actually useful
//for the application logic. would you look at that
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id")
private long mId;
#Column(name="answer_text")
private String mAnswer;
//got rid of long mPollId
//it was for the same reason i did in the Post class
//hibernate does the work for me with the mPoll object and the
//annotations i've provided on it
//made the relationship between a poll and its answers bidirectional
//not entirely sure how adding the below annotations to the new
//Poll field fixed my problems, but it did
//i imagine it somehow tells hibernate that the primary key
//for the below object is the foreign key represented by poll_id in the
//database table for this entity
//and making insertable=true enables hibernate to insert that foreign
//key into the appropriate column in the database when this entity
//is saved
//updatable seemed to be necessary
//hibernate complained when it wasn't there
//and nullable was in the helpful examples i found so it was copy and
//pasted along with the rest of the helpful stuff here
//this field can't be nullable anyways so semantically, it makes sense
//for it to be there
#ManyToOne
#JoinColumn(name="poll_id", nullable = false, insertable=true, updatable=false)
private Poll mPoll;
Final functioning query: does work
Session session = HibernateUtilities.openSession();
session.beginTransaction();
List<Post> usersFeed = session.createQuery("select p from Post p where p.mUserId = :userId")
.setString("userId", userId)
.list();
session.getTransaction().commit();
session.close();

#GeneratedValue in Oracle with no Sequence

I have created a trigger so that my entities ids are autogenerated with a sequence each time they're inserted into my Oracle database.
The problem comes with annotating these entities for Hibernate/JPA: I need to define a #GeneratedValue annotation but I don't want to specify the sequence name -- doing that will make Hibernate query the sequence first, then insert, which is a work that is already done by the trigger.
Is there any way to skip this sequence in the #GeneratedValue with the scenario I've proposed?
Exception I get if id is not provided:
org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): Pattern
Pattern class:
#Entity
#Table(name = "PATTERN")
public class Patron extends HistoricoAbstractEntity {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#Column(name = "ID_PATTERN")
private Integer idPattern;
#Column
private String description;
#Column(name = "NEGATIVE")
private Boolean isNegative;
#Column(name = "type")
private Integer type;
#Column(name = "N_DAYS")
private Integer numDays;
... (getters & setters)
}
From what your code,
What I can tell you is that its not related to #GeneratedValue, it specifies that the hibernate takes responsibility to generate and idetifier for your entity. In your case your are generating id your self, so you have to manually set the id for that particular entity. Then you won't get this error any more, the other thing that you can try is use of #PrePersist annotate a method with this and try assigning a value to id in it. I haven't tried this but this should work according to this answer on SO.
Assign Custom Identifier
If your id is being generated by the database then you should use #GeneratedValue(strategy=GenerationType.AUTO) on your id field along with your #Id annotation.

#embeddable vs #entity for a mapping a collection

This must be quite naive but I have a doubt on when to use #Entity and #Embeddable.
Say I have a User and Notification class.
#Entity
public class User{
//other properties
#onetomany
private List<Notification> notifications;
}
#Entity
public class Notification{
//properties
}
I understand that there will be tables for class User and Notification, and a third table for mapping.
What if I do it like this?
#Entity
public class User {
//other properties
#ElementCollection
private List<Notification> notifications;
}
#Embeddable
public class Notification{
//properties
}
I know this won't create a table for Notification. But I can still store my notification objects. I went through the documentation, but couple of doubts:
Is it based on whether I want to see class B as a seperate table?
Is there a performance difference b/w creating a table and an embeddable object?
What can I not do with embeddable object that I can do with a table other than directly querying the table?
NOTES
For anyone reading this question, this question too might help you.
Is it based on whether I want to see class B as a separate table?
Yes, when you use #Embedded, You embed that #Embeddable entity in #Entity class, which makes it to add columns for embedded entity in same table of #Entity class.
Is there a performance difference b/w creating a table and an embeddable object?
When you use #Embedded, for table creation, one query is required, also for inserting and selecting a row. But if you don't use it, multiple queries are required, hence, use of #Embedded yields more performance, we can say.
What can I not do with embeddable object that I can do with a table other than directly querying the table?
Removing the respective embedded entity may be, but there may be integrity constraint violations for this.
In JPA, there’s a couple ways to create composite key fields. Lets see the method using the #Embeddable annotation.
Let’s start with the Entity class.
#Entity
#Table
public class TraceRecord {
#Id
private TraceRecordPk id;
#Version
#Transient
private int version;
#Column(columnDefinition = "char")
private String durationOfCall;
#Column(columnDefinition = "char")
private String digitsDialed;
#Column(columnDefinition = "char")
private String prefixCalled;
#Column(columnDefinition = "char")
private String areaCodeCalled;
#Column(columnDefinition = "char")
private String numberCalled;
}
This is a pretty simple Entity class with an #Id and #Version field and a few #Column definitions. Without going into too much detail, you’ll see that the #Version field is also annotated #Transient. I’ve done this simply because my table also doesn’t have a column for tracking versions, but my database is journaled, so I’m not too concerned about versioning. You’ll also notice that the #Column fields have a value of “char” set on the columnDefinition attribute. This is because the fields in my table are defined as char and not varchar. If they were varchar, I wouldn’t need to do this since a String maps to a varchar field by default.
The #Id field is what I’m interested in right now. It’s not a standard Java type, but a class I’ve defined myself. Here is that class.
#Embeddable
public class TraceRecordPk implements Serializable {
private static final long serialVersionUID = 1L;
#Temporal(TemporalType.DATE)
#Column
private Date dateOfCall;
#Column(columnDefinition="char")
private String timeOfCall;
#Column(columnDefinition="char")
private String callingParty;
/**
* Constructor that takes values for all 3 members.
*
* #param dateOfCall Date the call was made
* #param timeOfCall Time the call was made
* #param callingParty Extension from which the call originated
*/
public TraceRecordPk(Date dateOfCall, String timeOfCall, String callingParty) {
this.dateOfCall = dateOfCall;
this.timeOfCall = timeOfCall;
this.callingParty = callingParty;
}
}
To make this class capable of being an #Id field on an Entity class, it needs to be annotated with #Embeddable like I mentioned earlier. The 3 fields I’ve selected for my composite key are just normal #Column definitions. Rather than create getters/setters for each field, I’ve simply implemented a constructor that takes values for all 3 fields, making any instance immutable. When annotating a class with #Embeddable, that class will need to implement Serializable. So I’ve added a default serialVersionUID to accomodate.
Now that you have a class created and annotated with #Embeddable, you can now use it as the type for an #Id field in your Entity class. Simple stuff eh.

Categories

Resources