I have the following mapping:
#Entity
public class Satellite implements Serializable, Comparable<Satellite> {
#NotNull #Id
private long id;
.....
#OrderColumn
#OneToMany(mappedBy = "satellite", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<DataModel> dataModel;
}
and a child entity:
#Entity #IdClass(value=DataModelPK.class)
public class DataModel implements Serializable, Comparable<DataModel> {
private static final long serialVersionUID = -3416403014857250990L;
#Id
private int orbit; // related to reference orbit file
private int dataPerOrbit; // in Gbit
#ManyToOne #Id
private Satellite satellite;
}
originally, DataModel was an embeddable entity, but for a better control over the primary key and the underlying structure of the db, I switched to a more traditional model.
The point is, during the loading of the entity now it generate a stack overflow!! I think there is some cyclic loading between those two entities and it got stuck!
I'm thinking to revert everything back to what it was, but I wish to understand why it gives me this error.
You have #IdClass for DataModel specified to be DataModelPK.class but your #Id annotation is on an int field.
This is a problem, it may be causing you stackoverflow but I am not certain.
Update I now see the second #Id annotation so I stand corrected, I will investigate furtuer.
Related
I'm new to JPA. Suppose I have these two entities:
//Imports
#Entity
#Table(name="article", schema = "sch_client")
public class Article implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private int price;
private int amount;
//Getters & setters
}
And
#Entity
#Table(name="purchase", schema = "sch_client")
public class Purchase implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#OneToMany
private List<Article> listArticle;}
I want to have something like a purchase contains many articles.
My question is: is it possible with only #OneToMany in Purchase class that points to Article class to have the desired relationship (a purchase contains many articles). Or to use a #OneToMany annotation I have to add a #ManyToOne on Article class. If so, why is is mandatory to add the #ManyToOne? any explanation please.
Thanks in advance.
First of all, I have write a misleading title, I will change it to make it more accurate:
Old title : In JPA, is it possible to use #OneToMany without using #ManyToOne?
New title : #OneToMany does not create the join table.
As I said, I'm new to JPA, my problem can appear dumb, I could delete the question, but I decided to keep it in case someone someday will face similar situation, it can help!
The join table of Purchase and Article was created every time I executed the code very normally, but I didn't notice!, I was checking the logs of NetBeans
and didn't see the join table, I was misled by those logs, I think that a join table doesn't appear in the logs (I hope that someone can confirm this information and make an edit of this answer).
I have created Purchase and Article in a new schema named: sch_sales. and the join table was created in public schema (PostgreSQL).
So, to make it more correct I added schema to #JoinTable as shown below, like this I will have all my tables in the same schema.
#Entity
#Table(name="purchase", schema = "sch_sales")
public class Purchase implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#OneToMany
#JoinTable(name="join_purchase_article", schema = "sch_sales", joinColumns = #JoinColumn(name="sales_fk"), inverseJoinColumns = #JoinColumn(name="article_fk"))
private List<Article> listArticle;
}
UPDATE :
I was having a 3rd table created containing the id of Purchase and Article (a join table) which is obviously not correct.
The normal "behavior" is to have an id_purchase column added in Article, in this page I have find how to have such a result.
To have the desired result, I used the code below:
#Entity
#Table(name="purchase", schema = "sch_sales")
public class Purchase implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#OneToMany
#JoinColumn(name="id_purchase")
private List<Article> listArticle;
}
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.
I have a bean structure as shown below. The problem that I am facing is while trying to persist XBean, I am able to save all the data (i.e. xName, pBean, qBean, rBean, kBeans are all visible in storage) but there is no entry for Y_BEAN.
I am pretty much new with JPA annotations so not really sure if what I have done is correct. The idea is to have multiple entries of XBean (i.e. as List) with one instance of YBean
XBean also will hold an instance of YBean as its parent so when I retrieve XBean I should get all the data. Is there something wrong with #ManyToOne annotation?
#Entity
#Table (name = "X_BEAN")
public class XBean implements XInterface {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Key key;
private String xName;
#OneToOne(cascade=CascadeType.ALL)
private PBean pBean;
#ManyToOne
#JoinColumn(name="y_id")
private YBean yBean;
#OneToOne(cascade=CascadeType.ALL)
private qBean qBean;
#OneToOne(cascade=CascadeType.ALL)
private RBean rBean;
#OneToMany (mappedBy="xBean", cascade=CascadeType.ALL)
private List<KBean> kBeans;
// getter setters for each are below ...
}
and structure of YBean is like below
#Entity
#Table (name = "Y_BEAN")
public class YBean implements XInterface {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Key key;
#OneToOne(cascade=CascadeType.ALL)
private ZBean zName;
#OneToOne(cascade=CascadeType.ALL)
private PBean pBean;
#OneToOne(cascade=CascadeType.ALL)
private RBean rBean;
#OneToMany (mappedBy="yBean", cascade=CascadeType.ALL)
private List<XBean> xBeans;
// getter setter for each are below ...
}
I am using Google App Engine's storage
You need cascade=CascadeType.PERSIST on your ManyToOne, to tell Hibernate to persist the YBean when it persists the XBean.
You should also think about whether you want the cascade attribute on the inverse OneToMany. With CascadeType.ALL, if you were to delete an instance of YBean, Hibernate will delete all associated XBeans (of which there may be zero, one, or many), because CascadeType.ALL means "apply persistence operations, including deletion, to any other entities accessible via this property or collection". If you didn't have CascadeType.ALL and you deleted a YBean that was referred to by one or more XBeans, then those XBeans would now referenced a non-existent YBean ID, so you'd probably need to do some cleanup in that case.
Both options are irrelevant if your business logic never deletes a YBean until it is not referred to by any XBeans, but if your business logic doesn't prevent the case, then you should cascade or not based on whether you want to get rid of the XBeans or whether you want to clean them up (but not delete them) to no longer refer to the YBean that's being deleted.
#ManyToOne
#JoinColumn(name="y_id")
private YBean yBean;
what is the column y_id ?
what is the definition of it?
you can try removing #JoinColumn(name="y_id") and let JPA handle it.
and also add fetch = FetchType.EAGER like this.
#OneToMany (mappedBy="yBean", cascade=CascadeType.ALL, fetch = FetchType.EAGER)
private List<XBean> xBeans;
I have a simple Java EE 7 Web App with Eclipselink and the TABLE_PER_CLASS inheritance strategy.
Following classes:
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
#Entity
public abstract class AbstractService implements Serializable {
private static final long serialVersionUID = 7041207658121699813L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne
#JoinColumn
private PersonGroup personGroup;
}
#Entity
public class Service extends AbstractService implements Serializable {
private static final long serialVersionUID = 3817106074951672799L;
}
#Entity
public class PersonGroup implements Serializable {
private static final long serialVersionUID = 3205092801888510996L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "personGroup")
private List<AbstractService> services;
}
In persistence.xml I do Drop&Create.
After creating the database, I have this tables:
abstractservice, service, persongroup
The point is now, that eclipselink creates the table abstractservice with (only(!)) the attribute persongroup_id (no "id" attribute). Why?
My understanding from TABLE_PER_CLASS is, that every attribute and key is going "down", so abstractservice should have no more attributes and should not exist.
My businesscase is, that I have a lot of subservice from AbstractService. I want to get all subservices from AbstractService with a special persongroup.
The AbstractServicetable has no entries, because everything is in Service.
With CriteriaBuilder I say:
Select from AbstractService where persongroup_id = 123;
The Criteria Api should build this (with some union, if more subservices would exist), because I have TABLE_PER_CLASS:
Select from Service where persongroup_id = 123;
Why is eclipselink creating persongroup_id in abstractService and how can I solve my case?
At the end the result of the query is always empty, because abstractService is empty...
Same question was asked here: http://www.eclipse.org/forums/index.php/t/406338/
and seems to be related to bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=265702 which was fixed but regressed. A new bug should be filed for it if you are seeing this in the latest version.
If you are only using a single Servide subclass, you might want to make it a mappedSuperclass instead. If not, a different inheritance type such as joined or single table is usually recommended. This bug seems to only affect DDL generation, so you can switch to have JPA create a script that you can then edit to remove the AbstractService table entries.
It took me hours to realize, what the problem is:
I have a Spring Rest service and a GET-Method which returns a user in JSON-Format.
The data comes from my database over sessionFactory.
After debugging it turned out, that the Problem is related to my bidrectional onetomany-manytoone relationship.
So calling
User user = (User) sessionFactory.getCurrentSession().load(User.class, userId);
returns a User-Object where user.getCity().getSupplier() runs into an com.sun.jdi.InvocationException. Therefore Jackson is obviously unable to serialize.
But what causes this exception?
#Entity
#Table(name = "T_CITY")
public class City implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private long id;
#OneToMany(mappedBy = "city", cascade=CascadeType.ALL)
private Set<User> user;
#OneToMany(mappedBy = "city", cascade=CascadeType.ALL)
private Set<Supplier> supplier;
User:
#Entity
#Table(name = "T_USER")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
public User() {
}
#Id
private long id;
#ManyToOne
private City city;
Supplier:
#Entity
#Table(name = "T_SUPPLIER")
public class Supplier implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private long id;
#ManyToOne
private City city;
As mentioned in the other answer, I think you'll find that your issues are related to the x-to-x relationships. This can sometimes create circular reference issues when trying to jsonify the entity beans.
Sometimes you can avoid or get past this by using annotations, other times a wrapper class is needed. I often just write a wrapper class to handle my JSON transactionts
There are many many references to this type of issues spanning many languages. Here a few starting points for you to research.
Google related search regarding circular references in entity objects
Json and Java - Circular Reference
Circular Dependencies With Jackson