I have a following problem with entity mapping in JPA. I have two entities, first one is Lookup and the second is Text which represents translations for entities. Now I need to bound Lookup to the Text but I don't want Text to have reference to Lookup. To make this more complicated, Text does not use its primary key in this relationship but a metacode defined in a TXTHEAD_CODE column.
Lookup.java
#Entity
#Table(name = "DATREG")
public class Lookup implements PersistableEntity {
#Id
#Column(name = "DATREG_META_CODE")
private String metaCode;
#OneToMany
#JoinTable(name="TXT",
joinColumns=#JoinColumn(name="DATREG_META_CODE", referencedColumnName="TXTHEAD_CODE"),
inverseJoinColumns=#JoinColumn(name="DATREG_META_CODE"))
private List<Text> text;
Text.java
#Entity
#Table(name = "TXT")
public class Text {
#Id
#Column(name = "TXT_ID")
private Long id;
#Column(name = "TXTHEAD_CODE")
private String code;
So I have tried this (and few other variations) but with no result. I also can't create join table in the DB and I don't want bound Lookup to my Text class. So can anyone please tell me if there is some other way?
My bible for JPA work is the Java Persistence wikibook. It has a section on unidirectional OneToMany which explains how to do this with a #JoinColumn annotation. In your case, i think you would want:
#OneToMany
#JoinColumn(name="TXTHEAD_CODE")
private Set<Text> text;
I've used a Set rather than a List, because the data itself is not ordered.
The above is using a defaulted referencedColumnName, unlike the example in the wikibook. If that doesn't work, try an explicit one:
#OneToMany
#JoinColumn(name="TXTHEAD_CODE", referencedColumnName="DATREG_META_CODE")
private Set<Text> text;
Related
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();
I am absolutly new in Hibernate development and I have the following problem.
I have 2 entity classes that maps 2 DB tables:
1) The first entity class (the main one) is named KM_ProjectInfo and map a DB table named KM_PROJECT.
2) The second entity class is named KM_ProjectInfoStatus and map a DB table named KM_PROJECT_INFO_STATUS.
So the second one represent a specific field of the first one (a status of the row representd by an instance of the KM_ProjectInfo class). Infact I have something like this:
1) KM_ProjectInfo class:
#Entity
#Table(name = "KM_PROJECT")
public class KM_ProjectInfo implements Serializable {
#Id
#GeneratedValue
private Long idProjectInfo;
#Column(name = "name")
private String name;
#Column(name = "technology")
private String technology;
#ManyToOne
#JoinColumn(name = "idCountry")
private KMCountry country;
#Column(name = "power")
private long power;
#Column(name = "cod")
private String cod;
#ManyToOne
#JoinColumn(name = "idProjectInfoStatus")
private KM_ProjectInfoStatus status;
// GETTERS & SETTERS
}
2) KM_ProjectInfoStatus:
#Entity
#Table(name = "KM_PROJECT_INFO_STATUS")
public class KM_ProjectInfoStatus implements Serializable {
#Id
#GeneratedValue
private Long idProjectInfoStatus;
#Column(name = "foldertech")
private Long foldertech;
#Column(name = "folderproject")
private Long folderproject;
// GETTERS & SETTERS
}
So, as you can see in the previous snippet, the KM_ProjectInfoStatuss is a field of the KM_ProjectInfo because I want that it contains the primary key of this table as foreign key.
In the logic of my application I want that at one row of the KM_PROJECT table (so at one instance of the KM_ProjectInfo entity class) is associated a single row of the KM_PROJECT_INFO_STATUS (one instance of the KM_ProjectInfoStatus entity class) because it represent a specific status for the KM_PROJECT row.
In my code I have:
#ManyToOne
#JoinColumn(name = "idProjectInfoStatus")
private KM_ProjectInfoStatus status;
but I think that is wrong because at one row of my first table it is associated a specific single row of the second table. But maybe I am missing something about how Hibernate work.
Can you help me to understand what I am missing? What it work? Why I have #ManyToOne instead #OneToOne?
Tnx
It all depends on how you want to model things. In terms of Database structure, OneToOne and ManyToOne are implemented in the same way:
One or more JoinColumns which makes a foreign key pointing to the primary key of the other table.
So both solutions correctly map to your database, but it depends if you want to allow several KM_ProjectInfo to point to the same KM_ProjectInfoStatus, or only allow a single one.
Note that, even though you would declare a OneToOne, you could still end up with multiple KM_ProjectInfo pointing to the same KM_ProjectInfoStatus if you don't manipulate Hibernate properly.
Here you did not declare the reverse relationship, but if you did, the declaration would have to be different:
In case of a OneToOne, you would have a KM_ProjectInfo member
In case of a OneToMany (reverse of ManyToOne), you would have a Collection<KM_ProjectInfo> member
From the description it seems you want to have one-to-one relationship. That is the project entity should have its very own status not shared by any other project. You could achieve this by using #OneToOne as below.
#Entity
#Table(name = "KM_PROJECT")
public class KM_ProjectInfo implements Serializable {
#Id
#GeneratedValue
private Long idProjectInfo;
#OneToOne
#JoinColumn(name = "idProjectInfoStatus")
private KM_ProjectInfoStatus status;
}
#Entity
#Table(name = "KM_PROJECT_INFO_STATUS")
public class KM_ProjectInfoStatus implements Serializable {
#Id
#GeneratedValue
private Long idProjectInfoStatus;
#OneToOne(mappedBy="idProjectInfoStatus")
private KM_ProjectInfo project;
}
This way you can have specific status for the KM_PROJECT.
Coming back to #ManyToOne, you will want to have this if you want to share the same status with multiple projects, but that's not what you want in your case. I have tried to explain mappings in simple way here One-to-One mapping.
For the context, client-side I use the MVP pattern, so the view with the One list knows only the ID, and when my new Many is received on the server, I want to be able to just update the One's foreign key, with a "setOneId" or an empty One object with an ID set to the wanted value.
So I try to create a many-to-one unidirectional in DataNucleus, and I'm struggling a bit. I'm ok to use JDO or JPA, I don't really care. In JPA, I tried this :
#Entity
public class Many {
#Id
String id;
#ManyToOne
#Join(name = "idOne")
One one;
}
#Entity
public class One {
#Id
String id;
}
It's almost what I want. The one-to-many is created but with a join table. I want to have a direct relation. And when I insert/update a Many, I don't want to insert/update the related One, just update the idOne with the good id in my Many object.
I found this blogpost, but it's with Hibernate, and I think it still use a join table :
#Entity
public class Many {
#Id
public String id;
#Column(name="idOne")
private String idOne;
#ManyToOne
#JoinColumn(name="idOne", nullable=false, insertable=false, updatable=false)
private One one;
}
I tried it, but I got exactly this error.
I don't understand how I am struggling with that. My goal is to have a table that keep some reference data (like a list of country as the class One), and a list of "working item" (like a town as the class Many) that I create/update without create/update the reference data, just its foreign key in the Many object.
If its a unidirectional association, and Many is the owning side (as per your second example), you are heading in the wrong direction. It doesn't make much sense to delegate the update and insert responsibility on the owning side of a unidirectional relationship (as done with the insertable=false and updateable=false).
EDIT: updated answer
So what you want is a many-to-one, with a foreign key column on the owning side. Try this
#Entity
public class Many {
#Id
String id;
#ManyToOne
#JoinColumn(name = "foreignKeyColumn")
One one;
}
#Entity
public class A {
#Id
String id;
#OneToOne(cascade=CascadeType.ALL)
B b;
}
#Entity
public class B {
#Id
String id;
}
and then if you persisted initial objects as
tx.begin();
A a = new A("FirstA");
B b1 = new B("FirstB");
B b2 = new B("SecondB");
a.setB(b1);
em.persist(a);
em.persist(b2);
tx.commit();
... (some time later)
tx.begin();
A a = em.find(A.class, "FirstA");
B b2 = em.getReference(B.class, "SecondB");
// update the B in A to the second one
a.setB(b2);
tx.commit();
This updates the FK between A and B. Can't get simpler
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.
I am using Hibernate and JPA. If I have two simple entities:
#Entity
#Table(name = "container")
public class Container {
#Id
#Column(name="guid")
private String guid;
}
#Entity
#Table(name="item")
public class Item {
#Id
#Column(name="guid")
private String guid;
#Column(name="container_guid")
private String containerGuid;
}
and I want to insure that inserting an Item fails if the referenced Container does not exist. I would prefer not to have a Container object populated inside the item object (ManyToOne), how would I do this if it is possible to do?
You can declare arbitrary constraint using columnDefinition attribute:
#Column(name="container_guid",
columnDefinition = "VARCHAR(255) REFERENCES container(guid)")
private String containerGuid;
Note, however, that Hibernate doesn't know anything about this constraint, so that, for example, it may not perform inserts in proper order with respect of it and so on.
Therefore it would be better to create a #ManyToOne relationship. If you are afraid of extra SQL query for Container needed to set this property, you can use Session.load()/EntityManager.getReference() to get a proxy without issuing actulal query.
Try using below relationship mapping
RelationShip Mapping
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#ManyToOne()
#ManyToMany()
<>
#JoinColumn(name="<>")