When trying to save an ID from my parent class into a child class, I keep getting the error
"ERROR - Field 'parent_id' doesn't have a default value"
I have tried all types of mappings. I am using annotations.
Any help on this would be appreciated
Parent:
#Id
#Column(name="id")
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#Column(name="description")
private String description;
#OneToMany
#Cascade(value= {org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.DELETE})
#JoinColumn(name="parent_id")
private List<Child> children;
Child:
#Id
#Column(name="id")
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#Column(name="description")
private String description;
Thanks.
A late addition in case anyone ever runs into the same issue.
This entity here, when persisted using Hibernate 4.1.8, will cascade the FieldChangeentities, but will not fill the join column:
#Entity
public class Event {
//ID and other fields here
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "event_id")
private List<FieldChange<?>> fields = new ArrayList<FieldChange<?>>();
}
Neither does the insert statement set the event_id column, nor does it update the inserted entity after the fact - the event_id remains null and the relation is lost.
If, however, the #JoinColumn definition is changed like this:
#JoinColumn(name = "event_id", nullable = false)
, then the insert statement includes the event_id column like it should, and all is well.
This may only be a regression in this particular version of Hibernate, but maybe it helps someone.
In your case JPA provider to persist child object with its parent perform at least three queries on db. First two persist the objects by its own. The last one
update child object with the foreign key referencing parent. The second query fail because you have a NOT NULL constraint on the foreign key column. You have three options:
Remove NOT NULL constraint on foreign key in the child entity
Use bidirectional relationship
Change JPA provider to one which supports such cases.
You must have something wrong somewhere else because those mappings will work the way they are. They could be better, but they'll work. Specifically, all the #Column annotations are redundant and unnecessary, and as non sequitor noted, you should use the cascade property of JPA's #OneToMany instead of Hibernate's #Cascade. I've created a runnable example with the cleaned-up version of what you posted. If you have git and maven, you can run it with:
git clone git://github.com/zzantozz/testbed tmp
cd tmp
mvn -q compile exec:java \
-Dexec.mainClass=rds.hibernate.UnidirectionalManyToOneJoinColumn \
-pl hibernate-unidirectional-one-to-many-with-join-column
It creates a parent with two children, saves them, and then loads them and prints out the graph. The output is:
Creating parent with two children
Loading saved parent
Parent{description='parent', children=[Child{description='child 2'}, Child{description='child 1'}]}
Change your #OneToMany to #OneToMany(cascade=CascadeType.ALL) use JPA rather than the Hibernate extensions
My guess is that the #JoinColumn annotation needs a referencedColumnName assigned.
#JoinColumn(name = "parent_id", referencedColumnName = "id")
Related
I have an hibernate managed entity:
#Entity
public class Parent {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// (omitted useless details)
#OneToOne
#JoinColumn(name = "child_id", updatable = false)
private Child child;
// (omitted useless details)
}
--
#Entity
public class Child {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// (omitted rest...this is a POJO)
}
Since the responsibility of the update for Child is managed elsewhere, my goal is to simply not update child when the parent is saved. Unfortunately, this updatable = false on the #JoinColumn appears to be getting ignored, saving any changes made to both parent and child.
How can I achieve only saving the parent in a one to one relationship?
Any help is appreciated.
EDIT: Clarification, the Child class is an #Entity as well, but a simple POJO. The relationship between Parent and Child is unidirectional from the parent.
I looked into this for quite a while and looking at the documentation for #JoinColumn annotation and the updatable/insertable properties it says...
"(Optional) Whether the column is included in SQL UPDATE statements generated by the persistence provider."
What this means is setting updatable = false will only prevent the foreign key from being updated (column is included). When you save the parent entity it will also save all child entities attached to the object.
This means that any child properties that are attached to the parent entity when you save will also be persisted. This brings another issue to light if someone else may have updated this child entity, but because you are saving the parent entity with the child entity attached to it, you will un-knowingly overwrite any changes made to the child object.
Solution:
AFAIK the only way to resolve this is to be diligent about the object you save, unless you really need to be saving/updating the child entities don't. Keep your objects self contained, this is the downfalls of lazy/eager loaded properties and saving that same object graph. You could also do like another poster said and set the child entity to null before the save to prevent any updates, but can easily be missed.
If you are OK with saving the entire object tree (parent and children entities) you could add a property that utilizes the #Version attribute to introduce optimistic concurrency. This way if any entity was updated by someone else and you are trying to save an old version it will fail.
#Version
#Column(name=”version”)
private long version;
public long getVersion() { return version; }
I have a many-to-one relationship between two objects: SomeProjectType and Work Orders. In SomeProjectType, I have:
#OneToMany(mappedBy = "project", fetch = FetchType.EAGER)
private Set<WorkOrder> workOrders;
SomeProjectType has a "ProjectKey" as the #id for it.
And in WorkOrder I have:
#ManyToOne
#JoinColumn(name = "WorkOrderProjectKey")
private SomeProjectType project;
The issue I am having is that sometimes in WorkOrder, the "WorkOrderProjectKey" has a project key that doesn't exist in SomeProjectType (I am not sure why, but it is by design).
My question is: Is there a way to have Hibernate still return back rows even if some do not match? I have tried "nullable=true" and "optional=true" but it still won't work.
try to this code because i have same problem then i will change code and work properly.
Primary Key Tables
#OneToMany(mappedBy = "project")
private List<WorkOrder> workOrders;
Foreign Key Table
#ManyToOne
#JoinColumn(name = "WorkOrderProjectKey")
private SomeProjectType project;
I got it to work! Under the #ManyToOne, I put the following and it gets everything.
#NotFound( action = NotFoundAction.IGNORE )
Got this from the answer here:
Hibernate chokes on missing rows when dealing with a legacy database
I'm working with JPA 2 + Hibernate 4 and I'm implementing some CRUD operations on model entities.
Now I need to prevent a certain entity (EntityB) to be deleted when a related entity (EntityA) exists in database:
#Entity
public class EntityA {
#Id
private int id;
#OneToOne(mappedBy = "entityA", optional = false, fetch = FetchType.LAZY)
private EntityB entityB;
//...
}
#Entity
public class EntityB {
#Id
private int id;
#OneToOne
#JoinColumn(name = "id")
private EntityA entityA;
//...
}
Is there any way to achieve this using relationship options or should I check EntityA existence in my dao/repository before removing EntityB?
NOTE I need this also for #ManyToOne relationships.
If you want to prevent that in your code, than simply do not delete that entity (by checking that manually). There is no possibility to do that with annotations.
On the other side, this sounds to me rather like a need for a DB constraint. If those entities are already related, then simply add a foreign key constraint (if none is existent). If not, than think of adding one.
PS: if you already have a relationship, check the CascadeType.REMOVE setting.
I don't think you can solve this with annotations. You should manally check related-entity existence before.
I'm mapping a database (Oracle 11g) to JPA entities using EclipseLink. I have mapped almost every table to JPA objects but I've just found a problem:
In the \Curve\ entity I have the following fields:
#Id
#Column(name = "COD_CURVE")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq.gen")
#SequenceGenerator(name = "seq.gen.curve", sequenceName = "SEQCURVE", allocationSize = 1)
private long codCurve;
#Id
#Column(name = "FEC_HISTORIC")
#Temporal(javax.persistence.TemporalType.DATE)
private Date fecHistoric;
#OneToMany(mappedBy="codCurve", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Collection<CurveDetail> detailsCollection;
In the \CurveDetail\ entity I have this:
#ManyToOne
#JoinColumns({
#JoinColumn(name = "COD_CURVE", referencedColumnName = "COD_CURVE"),
#JoinColumn(name = "FEC_HISTORIC", referencedColumnName = "FEC_HISTORIC")
})
private Curve codCurve;
The problem is that when I query the \Curve\ entity, the details always are null, despite the fact that there is valid data in both tables. Checking the database I've noticed that there are no foreign key constraints in the \CurveDetail\ table, so I wonder ¿Are these constraints required to map the database correctly? I haven't tried to add the FK constraint myself because I'm not allowed to (have to ask a DBA to do it, and it'll take a week).
Thanks in advance!
Having a foreign key is not required.
Check the SQL that is generated by enabling logging ("eclipselink.logging.level"="finest")
Try executing the same SQL with the same database to see if the data exists.
Also ensure you are not corrupting the shared cache by inserting/updating an object with a null collection. You must maintain both sides of a bi-directional relationship. You could try disabling the cache to see if this is what you are doing.
As I know having a FK constraint is not mandatory. Once I had the same problem (but it was Oracle 9i) and found out that the name of Entity class should match the name of the table you want to map, and also JPA SQL and Hibernate HQL are both case sensitive so be careful in writing #Column tag.
I have two tables: t_promo_program and t_promo_program_param.
They are represented by the following JPA entities:
#Entity
#Table(name = "t_promo_program")
public class PromoProgram {
#Id
#Column(name = "promo_program_id")
private Long id;
#OneToMany(cascade = {CascadeType.REMOVE})
#JoinColumn(name = "promo_program_id")
private List<PromoProgramParam> params;
}
#Entity
#Table(name = "t_promo_program_param")
public class PromoProgramParam {
#Id
#Column(name = "promo_program_param_id")
private Long id;
//#NotNull // This is a Hibernate annotation so that my test db gets created with the NOT NULL attribute, I'm not married to this annotation.
#ManyToOne
#JoinColumn(name = "PROMO_PROGRAM_ID", referencedColumnName = "promo_program_id")
private PromoProgram promoProgram;
}
When I delete a PromoProgram, Hibernate hits my database with:
update
T_PROMO_PROGRAM_PARAM
set
promo_program_id=null
where
promo_program_id=?
delete
from
t_promo_program
where
promo_program_id=?
and last_change=?
I'm at a loss for where to start looking for the source of the problem.
Oh crud, it was a missing "mappedBy" field in PromoProgram.
Double-check whether you're maintaining bidirectional association consistency. That is; make sure that all PromoProgramParam entities that link to a PromoProgram as its parent are also contained in said parent's params list. It's a good idea to make sure this happens regardless of which side "initiates" the association if you will; if setPromoProgram is called on a PromoProgramParam, have the setter automatically add itself to the PromoProgram's params list. Vice versa, when calling addPromoProgramParam on a PromoProgram, have it set itself as the param's parent.
I've encountered this problem before as well, and it was due to not maintaining bidirectional consistency. I debugged around into Hibernate and found that it was unable to cascade the delete operation to the children because they weren't in the list. However, they most certainly were present in the database, and caused FK exceptions as Hibernate tried to delete only the parent without first deleting its children (which you've likely also encountered with the #NonNull in place).
FYI, I believe the proper "EJB 3.0"-way of making the PromoProgramParam.promoProgram field (say that a 100 times) non-nullable is to set the optional=false attribute on the #ManyToOne annotation.