GraphQL Spring Boot: Parent field retrieve null id wrongly - java

I have an "Organization" class that has "Organization parent" field. It's fetch type is lazy and relation is Many-To-One;
#Entity
#Table(name = "organization", uniqueConstraints = {#UniqueConstraint(columnNames = {"name",
"code"})})
public class Organization extends BaseDomain {
private String name;
private String baseUrlBackend;
private String baseUrlFrontend;
private String code;
private Organization parent;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn
public Organization getParent() {
return parent;
}
.
.
.
when i am trying to get organization with it's id i'm getting this error;
as i can understand i am having this trouble because;
"Organization parent" is nullable but an "Organization" class has to have an "id" value.
But if there is no parent, there can't be any id value neither. Is there an annotation or config file to solve that problem.
So far i tried some solutions. When i change the FetchType.LAZY to FetchType.EAGER problem is solved but i don't want to change the FetchType so im looking for different solutions.

Related

JPA Hibertane unidirectional one-to-one with shared primary key save parent first NO REVERSE

I'v been searching internet for answer, but nothing was working for me. There is a lot of topics with similar cases but specific details are different in a way that make them unusable for me.
So I have two tables: t_item and t_item_info:
item_id field from t_item_info table references id field from t_item table. I'm using mysql db and id column form t_item is auto incremented
I need to make unidirectional one-to-one mapping in a specific way. Here are my classes:
#Entity
#Table(name = "t_item")
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false)
#PrimaryKeyJoinColumn(name = "id", referencedColumnName = "item_id")
private ItemInfo info;
}
And other one
#Entity
#Table(name = "t_item_info")
public class ItemInfo {
#Id
private Long itemId;
private String descr;
}
So the point is that i need Item object to have a reference to ItemInfo object. NOT The other way!
Item -> ItemInfo --YES
Item <- ItemInfo --NO
The other thing is that i need parent (Item) id to become id for a child (ItemInfo)
For example I create Item object with null id and set it's info field with ItemInfo object which also have null id field. Like this:
{
"id": null,
"name": "Some name",
"info": {
"itemId": null,
"descr": "some descr"
}
}
Then when Item object persists hibernate should generate id for parent(Item) object and set it as itemId field for child(ItemInfo).
I have been trying to achieve this with different hibernate annotations and I noticed that no matter how hard I tried Hibernate always seems to try to persist child object first. I noticed it in the logs when I turned sql logging on. insert into t_item_info always goes first (and dies because of null id :D)
So the question is: Is it even possible to achieve this and if so what should I change in my code to do so
I hope that what I'm trying to ask makes sens to you given my poor explanations =)
Why people always insist the child object table in one-to-one associations should be the one with the foreign key is beyond me.
Anyway, as a workaround, since both objects share the id and the association is non-optional, you might as well declare the autogenerated key for the child object:
#Entity
#Table(name = "t_item_info")
public class ItemInfo {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long itemId;
private String descr;
}
and then use #MapsId for the parent:
#Entity
#Table(name = "t_item")
public class Item {
#Id
private Long id;
private String name;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "id")
#MapsId
private ItemInfo info;
}
Note that this approach, will, in a sense, fool Hibernate into thinking it is the Item that should be treated as the child object. You have been warned.
While there is an accepted answer here it looks to me like #Secondary table would be a better and more convenient solution: you may have 2 tables at the database level but I do not see any reason that that fact needs be exposed to any client code. There does not seem to be a lot of benefit to that? The following gives you a simpler API.
Entity:
#Entity
#Table(name = "t_item")
#SecondaryTable("t_item_info", pkJoinColumns={
#PrimaryKeyJoinColumn(name="id", referencedColumnName="item_id")})
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#Colulumn(name = "description", table= "t_item_info"")
private String description;
}
API:
{
"id": null,
"name": "Some name",
"descr": "some descr"
}

Hibernate Unidirectional OneToMany Not Working with composite id

I've been bashing my head on my keyboard for two days trying to figure this out...
Some background: We have a data model set up with a Perl code base that runs straight native SQL statements to the database via ODBC. For certain reasons, we decided to rewrite the code in Java... I thought it would be a good idea to use Hibernate to define all of the mappings. We don't want to edit the data model.
For simplicity sake, I can express the problem with only part of our data model. We have the entities "Job","JobDatabase" and "JobTable".
Job has a PK of job_name. Database has a PK of job_name,name. Table has a PK of job_name,src_database_name,name. As you may expect, Job has a OneToMany relationship with JobDatabase, and Database has a OneToMany with JobTable.
For purposes of this test, I'm starting with empty tables and trying to create some sample data. I can insert a Job and a JobDatabase, but when I try to insert the JobTable, Hibernate throws an error. Or more accurately, that is where it complains. It doesn't start executing my code because it detects the mapping error. However, if I remove the association between JobDatabase and JobTable, it will insert all Job and JobDatabase records correctly with no errors.
Sample Classes (all fields have getters/setters... there are also many other fields):
#Entity
#Table(name="Job")
public class Job implements Serializable {
#Id
#Column(name="job_name",nullable = false)
private String jobName;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "job_name", referencedColumnName = "job_name")
private Set<JobDatabase> databases;
}
#Entity
#Table(name="JobDatabase")
public class JobDatabase implements Serializable {
#Id
#Column(name="job_name",nullable = false)
private String jobName;
#Id
#Column(name="name",nullable = false)
private String name;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumns({
#JoinColumn(name = "job_name", referencedColumnName = "job_name"),
#JoinColumn(name = "name", referencedColumnName = "src_database_name")
})
private Set<JobTable> tables;
}
#Entity
#Table(name="JobTable")
public class JobTable implements Serializable{
#Id
#Column(name="job_name",nullable = false)
private String jobName;
#Id
#Column(name="src_database_name",nullable = false)
private String srcDatabaseName;
#Id
#Column(name="name",nullable = false)
private String name;
}
The error:
Exception in thread "main" org.hibernate.MappingException: Unable to find column with logical name: src_database_name in JobDatabase
I keep getting this error. I do not understand why it is looking for the referenced column in the entity "owning" the mapping. src_database_name does indeed only exist in JobTable - it is referred to as "name" in JobDatabase. JobTable also has a "name" field, but it refers to the name of the Table.
You need to have src_database_name column in your JobDatabase table. Or you can change src_database_name to other column name.
For composite key reference column must be present in your source table.

Incomplete #JoinColumns

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;
...
}

#OneToMany with #JoinFormula using polymorphism and generic

I have the following use case:
Parents contain Children and ParentTags.
Children contain ChildrenTags and their Parent node.
Both ParentTags and ChildrenTags are Tags with T being Parent or Child.
Now I want a derived field in Parent that map all tags relative to this parent or to one of its children.
The SQL query is straightforward but I can't make it work by annotating a given property.
Note that the #ManyToOne mapping works like a charm in order to find the Parent owner of a tag, cf my code below (this is a #OneToMany relation, Tag is maybe not the best name I could find for this example).
Parent.class
#Entity
#Audited
public class Parent {
#Id
private Long id;
#OneToMany(mappedBy = "parent")
private List<Child> children;
#OneToMany(mappedBy = "parent")
private List<ParentTag> tags;
// Does not work!
#OneToMany(mappedBy = "owner")
private List<Tag<?>> allTags;
}
Child.class
#Entity
#Audited
public class Child {
#Id
private Long id;
#ManyToOne
private Parent parent;
#OneToMany(mappedBy = "child")
private List<ChildTag> tags;
}
Tag.class
#Entity
#Audited
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Tag<T> {
#Id
private Long id;
protected String value;
#NotAudited // otherwise ClassCastException
#ManyToOne
#JoinColumnsOrFormulas({
#JoinColumnOrFormula(formula = #JoinFormula(
value = "CASE WHEN parent_id IS NOT NULL THEN parent_id WHEN child_id IS NOT NULL THEN (SELECT child.parent_id FROM Child child WHERE child.id = child_id) end",
referencedColumnName="id"))
})
private Parent owner;
public abstract T getNode();
}
ChildTag.class
#Audited
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class ChildTag extends Tag<Child> {
#ManyToOne
private Child child;
#Override
public Child getNode() {
return child;
}
}
ParentTag.class
#Audited
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class ParentTag extends Tag<Parent> {
#ManyToOne
private Parent parent;
#Override
public Parent getNode() {
return parent;
}
}
I'd like to find a way to load allTags by a given query or formula.
The inverse mapping #ManyToOne works (as long as owner is not audited, it was hard to find that bug).
I already tried the following solutions without success:
#JoinFormula
#JoinColumnsOrFormulas({
#JoinColumnOrFormula(formula = #JoinFormula(
value = "CASE WHEN parent_id IS NOT NULL THEN parent_id WHEN child_id IS NOT NULL THEN (SELECT child.parent_id FROM Child child WHERE child.id = child_id) end",
referencedColumnName="id"))
})
private List<Tag<?>> allTags;
I get a ClassCastException, Formula cannot be cast into a Column
#Loader
#Entity
#Audited
#NamedNativeQuery(name = "loadAllTags",
query = "SELECT * FROM Tag tag WHERE "
+ "(tag.parent_id IS NOT NULL AND tag.parent_id = :id) OR "
+ "(tag.child_id IS NOT NULL AND EXISTS (SELECT 1 FROM Child child WHERE child.id = tag.child_id AND child.parent_id = :id))")
public class Parent {
...
#Loader(namedQuery = "loadAllTags")
private List<Tag<?>> allTags;
}
No exception, actually when debugging I can see that the loader find all appropriate tags, but does not initialize the collection with them.
I also tried to put the query in a hbm configuration file, as I understood that #Loader and #NamedNativeQuery do not get along well, but without success (maybe I did something wrong here). However I'd rather implement a solution without configuration file.
I could add another column (owner_id) but if I can find a way to solve that problem without changing the model, it would be better.
I don't know if generics have something to do with it. In addition my entities are audited and indexed.
Any help will be greatly appreciated!

How do I avoid NullPointerException with OneToOne mapping against a parent entity class?

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.

Categories