I'm having a problem with JPA when trying to create some models to my database.
I have these three classes (I'll just put part of the code here):
GuideVersionLang
#Entity
public class GuideVersionLang implements LangItem {
...
#ManyToOne
#JoinColumns({
#JoinColumn(name="GUIDE_VERSION_NUMBER", referencedColumnName="VERSION_NUMBER"),
#JoinColumn(name="GUIDE_ID", referencedColumnName="GUIDE_ID")
})
#JsonIgnore
private GuideVersion guideVersion;
...
}
GuideVersion
#Entity
#IdClass(value=GuideVersionKey.class)
public class GuideVersion {
...
#OneToMany(mappedBy="guideVersion", orphanRemoval=true, cascade=CascadeType.PERSIST)
private LangsCollection<GuideVersionLang> guideVersionLangs;
#Id
#ManyToOne
#JoinColumn(nullable = false, name="GUIDE_ID")
#JsonIgnore
private Guides guide;
#Id
#Column(name = "VERSION_NUMBER")
private long versionNumber;
...
}
And GuideVersionKey
#Embeddable
public class GuideVersionKey {
private long versionNumber;
private long guide;
...
}
So, I have a GuideVersion class and this class has a composite key. Its composite key is composed by the id of a Guide and a versionNumber, both long numbers.
I just want to make a relation between GuideVersion and GuideVersionLang, as you can see in the code. However, I'm having problems on the #JoinColumns annotation:
#JoinColumns({
#JoinColumn(name="GUIDE_VERSION_NUMBER", referencedColumnName="VERSION_NUMBER"),
#JoinColumn(name="GUIDE_ID", referencedColumnName="GUIDE_ID")
})
I don't know why but the #JoinColumns is not working. I'm getting this error:
The #JoinColumns on the annotated element [field guideVersion] from
the entity class [class com.model.GuideVersionLang] is incomplete.
When the source entity class uses a composite primary key, a
#JoinColumn must be specified for each join column using the
#JoinColumns. Both the name and the referencedColumnName elements must
be specified in each such #JoinColumn.
As you can see in the code, I am specifying both #Id columns inside the #JoinColumns annotation. What am I missing here?
Thank you VERY much!
There is some tips about the code in question:
1.as you have an embedded id for GuideVersion (GuideVersionKey ) so you really don't need to specify Ids for it (just use #EmbeddedId annoation).
2.you can map the Guid_id with #MapsId.
#Entity
public class GuideVersion {
...
#EmbeddedId
GuideVersionKey IdKey;
#ManyToOne
#MapsId("guide")
#JoinColumn(name = "GUIDE_ID")
private Guides guide;
...
}
Related
I have a simple table (ActivityLog) and I want it to have a PK that is also a FK to another table (User).
It seems to be a common thing to have, and I tried to follow this wikibook
Primary Keys through OneToOne and ManyToOne Relationships. The example there involved a composite key. I need just a primitive key, so I ended up with:
#Entity
public class User {
#Id
private Long id;
// other stuff
}
#Entity
public class ActivityLog {
#Id
#OneToOne(optional = false)
#JoinColumn(name="user_id", referencedColumnName="id")
private User user;
// other stuff
}
Unfortunately i am getting:
Caused by: java.lang.IllegalArgumentException: This class [class com.example.ActivityLog] does not define an IdClass
at org.hibernate.metamodel.internal.AbstractIdentifiableType.getIdClassAttributes(AbstractIdentifiableType.java:183)
at org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation$IdMetadata.<init>(JpaMetamodelEntityInformation.java:253)
I tried to annotate ActivityLog with:
#IdClass(Long.class)
(even though from what I understand it is applicable only for composite keys), yet I am getting the exact same error.
Is my case different than what's on the mentioned wikibook?
Is Spring at fault here? (As suggested in this question? (no accepted answers)).
This should help:
#Entity
public class ActivityLog {
#Id
#Column(name = "user_id")
private Long id;
#OneToOne(optional = false)
#JoinColumn(name="user_id", referencedColumnName="id")
private User user;
// other stuff
}
Btw. I would expect, that you need more logs per user, so you would probably need some additional (generated) id anyway ...
I am using eclipselink 2.5.1.
Let's say I have these two class.
JAVA
#Entity
public class Car implements Serializable {
#EmbeddedId
protected CarPK carPK;
private String color;
#ManyToOne(fetch = FetchType.LAZY)
private Manufacturor manufacturor;
//constructors, getters & setters...
}
#Embeddable
public class CarPK implements Serializable {
#NotNull
private int idManufacturor;
#Temporal(javax.persistence.TemporalType.DATE)
private Date date;
//constructors, getters & setters...
}
Car has a composite primary key (idManufacturor and date) and idManufacturor is also a foreign key referencing the class Manufacturor.
I'm having issue with the mapping. EclipseLink understand the manufacturor object as a column in my Car table.
Error
Internal Exception: com.microsoft.sqlserver.jdbc.SQLServerException: invalid column nameĀ : 'manufacturor'.
I know the problem will be solved if I add a column manufacturor FK but it would be repeating.
Please feel free to ask for any precision if I'm not clear enough.
Thank you for your help.
Add the JoinColumn Annotation
#JoinColumn(name = "id_manufacturor", referencedColumnName = "id")
Name is the FK column name in your database (not entity).
The referencedColumnName "id" must correspond to the defined id in manufacturer table.
I have the following relation in database:
I have one strong table.
I have one weak table that has one to one relation with strong table. Really it's 0 to 1 relation, because strong table doesn't have always one line in weak table. To identify this weak table is enough the Id of strong table.
And finally I have another weak table, with ManyToOne relation with first weak entity. It needs the id of OneToOneWeakEntity (that also is id of strong table), and his own id. It's like an historical of OneToOneWeakTable.
I want to map in Hibernate, but I don't know how to do it.
Now I have the following code:
#Entity
#Table(name="table")
public class Table {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="id_table")
private Integer idTable;
private String otherAtributes;
....
}
#Entity
#Table(name="oneToOneWeakTable")
public class OneToOneWeakEntity {
#OneToOne(cascade = CascadeType.ALL, optional=false)
#Id
#JoinColumn(name="table_id_table")
private Table table;
private String otherAtributes;
....
}
#Entity
#Table(name="oneToManyWeakTable")
#IdClass(EntityPk.class)
public class OneToManyWeakTable {
#Id
#ManyToOne
#JoinColumn(name="table_id_table")
private OneToOneWeakEntity oneToOneWeakEntity;
#Id
#Column(name="own_id")
private String ownId;
private String otherAtributes;
....
}
class EntityPk {
#Id
#ManyToOne
#JoinColumn(name="table_id_table")
private OneToOneWeakEntity oneToOneWeakEntity;
#Id
#Column(name="own_id")
private String ownId;
private String otherAtributes;
....
}
My problem is when I try to run my application, because I have this deployment error:
Caused by: org.hibernate.AnnotationException: A Foreign key refering package.OneToOneWeakEntity from package.OneToManyWeakTable has the wrong number of column. should be 0
at org.hibernate.cfg.annotations.TableBinder.bindFk(TableBinder.java:502)
at org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.java:117)
at org.hibernate.cfg.Configuration.processFkSecondPassInOrder(Configuration.java:1518)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1422)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1846)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1930)
How can I map this relation??
Thanks!
Edit: I also try with this to map OneToOneWeakTable:
#OneToOne(cascade = CascadeType.ALL, optional=false)
#PrimaryKeyJoinColumn
#Id
#JoinColumn(name="table_id_table")
private Table table;
In this case, I also have an error when I try to deploy, but a different exception:
Caused by: java.lang.NullPointerException
at org.hibernate.cfg.Ejb3JoinColumn.checkReferencedColumnsType(Ejb3JoinColumn.java:568)
at org.hibernate.cfg.BinderHelper.createSyntheticPropertyReference(BinderHelper.java:258)
at org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.java:116)
at org.hibernate.cfg.Configuration.processFkSecondPassInOrder(Configuration.java:1518)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1422)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1846)
You don't have to repeat the annotations in the EntityPK class, you just need to match simple primitive attribute that represent the compound key of OneToManyWeakTable, you should get something like this (note insertable and updatable attributes, it has no sense modify the association because it is part of entity instance's pk),
#Entity
#Table(name="oneToManyWeakTable")
#IdClass(EntityPk.class)
public class OneToManyWeakTable {
#Id
#Column(name="table_id_table")
private long weakEntity
#ManyToOne
#JoinColumn(name="table_id_table", insertable=false, updatable=false)
private OneToOneWeakEntity oneToOneWeakEntity;
#Id
#Column(name="own_id")
private String ownId;
private String otherAtributes;
....
}
class EntityPk {
private long weakEntity;
private String ownId;
....
}
#Entity
#Table(name="oneToOneWeakTable")
public class OneToOneWeakEntity {
#OneToOne
#Id
#JoinColumn(name="table_id_table")
private Table table;
private String otherAtributes;
....
}
Also take a look at some official doc of compound primary keys
Edit: add the OneToOneWeakTable assuming that you are using JPA 2, in your edit you are mixing annotation. Check the id fileds and attribute that share the entities, must be same type (note that I use long for weakEntity attribute just as an example).
I have a LocalizedString Embeddable that looks like this:
#Embeddable
public class LocalizedString {
#ElementCollection(fetch = FetchType.EAGER)
private Map<String, String> stringMap;
// getter, setter
}
and an Article class that is supposed to make use of the LocalizedString:
#Entity
public class Article {
#Id
#GeneratedValue
private long id;
#Embedded
private LocalizedString title;
#Embedded
private LocalizedString text;
// getter, setter
}
Generating the tables works just fine, but when I try to insert an Article I get the following exception:
Duplicate entry '1-test2' for key 'PRIMARY'
After looking at the database structure it's obvious why. Hibernate only generated one article_string_map table with the a primary key constraint over the article id and the key of the map.
Googling this problem led me to this question on SO and the answer to include the #AttributeOverride annotations:
#Entity
public class Article {
#Id
#GeneratedValue
private long id;
#AttributeOverride(name="stringMap",column=#Column(name="title_stringMap"))
#Embedded
private LocalizedString title;
#AttributeOverride(name="stringMap",column=#Column(name="text_stringMap"))
#Embedded
private LocalizedString text;
}
This does not work either though, since Hibernate now complains about this:
Repeated column in mapping for collection:
test.model.Article.title.stringMap column: title_string_map
I do not understand what exactly is causing this error and I couldn't really translate the things I did find out about it to my specific problem.
My question is, what else do I need to fix to make LocalizedString work as an Embeddable? I'd also like to know why Hibernate is saying that I mapped title_string_map twice, even though I don't mention it twice in my entire project. Is there some kind of default mapping going on that I need to override?
How can I tell Hibernate to map this correctly?
(Also, I don't have a persistence.xml since I'm purely using annotations for configuration)
I figured it out on my own.
In order to map a ElementCollection I had to use #AssociationOverride combined with the joinTable attribute. The working Article class looks like this now:
#Entity
public class Article {
#Id
#GeneratedValue
private long id;
#AssociationOverride(name = "stringMap", joinTable = #JoinTable(name = "title_stringMap"))
#Embedded
private LocalizedString title;
#AssociationOverride(name = "stringMap", joinTable = #JoinTable(name = "text_stringMap"))
#Embedded
private LocalizedString text;
// getters, setters
}
I have searched and found similar issues, but they don't quite seem to be the same problem as
Why am I getting this NullPointer exception?
OneToOne Mapping with hibernate/JBoss/Seam
ANN-613 - NPE when mappedBy property is wrong on a #OneToOne
ANN-558 - #OneToMany(mappedBy="") can not recognize properties in parent classes
Hibernate Users - NPE with #Id on #OneToOne
I have a few entities mapped like this:
Person
|
+--User
I want to add a new entity PersonPartDeux with a OneToOne mapping to Person. The resulting mapping should look something like this:
Person + PersonPartDeux
|
+--User
When I do so, a NullPointerException is thrown while trying to load the mapping:
java.lang.NullPointerException
at org.hibernate.cfg.OneToOneSecondPass.doSecondPass(OneToOneSecondPass.java:135)
How do I specify the mapping so I can avoid this exception?
Here's my code:
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public abstract class Person implements Serializable
{
#Id
#GeneratedValue
public Long id;
#Version
public int version = 0;
public String name;
#OneToOne(cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn
public PersonPartDeux personPartDeux;
}
#Entity
public class PersonPartDeux implements Serializable
{
#Id
#GeneratedValue(generator = "person-primarykey")
#GenericGenerator(
name = "person-primarykey",
strategy = "foreign",
parameters = #Parameter(name = "property", value = "person")
)
public Long id = null;
#Version
public int version = 0;
#OneToOne(optional=false, mappedBy="person")
public Person person;
public String someText;
}
#Entity
#PrimaryKeyJoinColumn(name = "person_Id")
public class User extends Person
{
public String username;
public String password;
}
As for why I'm bothering, I need both the inheritance and the OneToOne mapping to solve different known issues in my application.
Attach the Hibernate source to your project, so you can click thru or 'Open Type' (Ctrl-Shift-T in Eclipse) to view the OneToOneSecondPass source.
Seeing the source, will give you a clear indication as to what needs to be specified.
In my source (Hibernate 4.1.7), line 135 is
propertyHolder.addProperty( prop, inferredData.getDeclaringClass() );
However you're probably using an earlier version.
Looking at the mappings, I'm suspicious of the #OneToOne definition -- mappedBy="person".
#OneToOne(optional=false, mappedBy="person")
public Person person;
What does it usefully mean, to map an association property by itself? Hibernate already knows the property is a OneToOne -- you just told it that.
Pointing the underpinning mapping/ FK of the property, at itself.. probably isn't actually telling Hibernate any correct or useful information.
Here's an example from the HB dosc, perhaps showing better how to do what you want:
#Entity
class MedicalHistory implements Serializable {
#Id Integer id;
#MapsId #OneToOne
#JoinColumn(name = "patient_id")
Person patient;
}
#Entity
class Person {
#Id #GeneratedValue Integer id;
}
Source: http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/
(3.5 docs off JBoss site.)
Cheers, hope this helps.