I have a class A{Set b .....} which holds references of class B as Set. It is one to many relationship.
Both class have sequencer in oracle. I put cascade to all in hibernate annotations. When i save class A, it gives me error that cannot insert null B.a_id . A-id is not nullable in my database. How can i persist this relationship.
This is a unidirectional relationship from A->B. a_id column in table B is not nullable. When hibernate tries to save class B, it not able to find value for a_id.
Well, did you try to make the JoinColumn non nullable?
#OneToMany
#Cascade({CascadeType.ALL})
#JoinColumn(name="A_ID", nullable=false)
private Set<B> b;
See also
Hibernate Core Reference Guide
6.2.1. Collection foreign keys
I ran into the same problem and solved it by using the mappedBy attribute of the #OneToMany annotation in Class A:
#OneToMany(cascade = CascadeType.ALL, mappedBy = "m_a")
private Set<B> b;
Here, m_a is the field in Class B that refers to Class A:
#JoinColumn(name = "aId", nullable = false)
#ManyToOne
private A m_a;
This way, the #JoinColumn is only specified in one place, no duplicated code.
Related
Currently, my database is organized in a way that I have the following relationships(in a simplified manner):
#Entity
class A {
/*... class A columns */
#Id #NotNull
private Long id;
}
#Entity
#Immutable
#Table(name = "b_view")
class B {
/* ... same columns as class A, but no setters */
#Id #NotNull
private Long id;
}
The B entity is actually defined by a VIEW, which is written in this manner(assuming Postgres):
CREATE VIEW b_view AS
SELECT a.* FROM a WHERE EXISTS
(SELECT 1 FROM filter_table ft WHERE a.id = ft.b_id);
The idea here is that B references all elements of A that are present on filter_table. filter_table is another view that isn't really important, but it's the result of joining the A table with another, unrelated table, through a non-trivial comparison of substrings. These views are done so that I don't need to duplicate and control which elements of A also show up in B.
All of these are completely fine. JpaRepository is working great for B(obviously without saving the data, as B is Immutable) and it's all good.
However, at one point we have an entity that has a relationship with B objects:
#Entity
class SortOfRelatedEntity {
/** ... other columns of SortOfRelatedEntity */
#ManyToOne(fetch = FetchType.EAGER, targetEntity = Fornecedor.class)
#JoinColumn(name = "b_id", foreignKey = #ForeignKey(foreignKeyDefinition = "references a(id)"))
private B b;
}
For obvious reasons, I can't make this foreign key reference "b", since B is a view. However, I do want the query for searching this attribute to be defined by the b_view table, and having the foreign key defined by the underlying table(as written above) would be also nice in order to guarantee DB integrity.
However, when applying the above snippet, my sort-of-related-entity table doesn't create a foreign key as I would have expected. For the record, I'm using Hibernate 5.2.16 atm.
What am I doing wrong? Is this even possible? Is there something else I should do that I'm not aware of?
Oh FFS
I realized my mistake now. This:
#JoinColumn(name = "b_id", foreignKey = #ForeignKey(foreignKeyDefinition = "references a(id)"))
Should have been this:
#JoinColumn(name = "b_id", foreignKey = #ForeignKey(foreignKeyDefinition = "foreign key(b_id) references a(id)"))
Notice that the foreignKeyDefinition must include foreign key(), not just the references part.
Hopefully this helps someone in the future.
I have the following problem (pseudo-java-code):
Let me a class A,B,C with the following relationships:
#Entity
#Table(name = "A")
public class A {
#OneToMany(mappedBy = "a")
private B b;
}
#Entity
#Table(name = "B")
public class B {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "a_id")
private A a;
#OneToOne(mappedBy = "b", fetch = FetchType.LAZY)
private C c;
}
#Entity
#Table(name = "C")
public class C {
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "b_id")
private B b;
}
I'm using JpaRepository with #Query annotation and I implemented the following query:
#Query("SELECT DISTINCT(a) FROM A a "
+ "LEFT JOIN FETCH a.b as b"
+ "WHERE a.id = :id ")
A findById(#Param("id") Integer id);
I want retrieve the informations about class A and B, but not C.
Somehow (I don't know why) the query try to retrive also the relation between B and C.
And then, with hibernate, start the lazy invocation for retrieving C.
Naturally, if I fetch also the relation between B and C (adding LEFT JOIN FETCH b.c as c) that's not happen.
My question is, why? Why I'm forced to fetch all nested relations and not only the ones which I need?
thank you.
Carmelo
Nullable #OneToOne relation are always eager fetched as explained in this post
Making a OneToOne-relation lazy
Unconstrained (nullable) one-to-one association is the only one that
can not be proxied without bytecode instrumentation. The reason for
this is that owner entity MUST know whether association property
should contain a proxy object or NULL and it can't determine that by
looking at its base table's columns due to one-to-one normally being
mapped via shared PK, so it has to be eagerly fetched anyway making
proxy pointless.
Shot in the dark, but there are some issues with lazy-loading #OneToOne-relationships. At least in older versions of Hibernate. I think (but can't seem to find any documentation) that this was fixed in one of the newer versions, so if you are not using a new version of Hibernate, try upgrading.
I've been searching over the web to find out a solution for this. It seems nobody has the answer... I start thinking i'm in wrong way adressing the problem.
Let's see if i can explain easy.
Im developing a contract maintenance. (table: contrat_mercan). For the contract, we will select a category (table: categoria), each category has qualities (table: calidad) in relation 1 - N (relationship table categoria_calidad).
This qualities must have a value for each contract where the category is selected, so I created a table to cover this relationship: contrato_categoria_calidad.
#Entity
#Table(name = "contrato_categoria_calidad")
public class ContratoCategoriaCalidad implements Serializable{
// Constants --------------------------------------------------------
private static final long serialVersionUID = -1821053251702048097L;
// Fields -----------------------------------------------------------
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "CCC_ID")
private int id;
#Column(name = "CONTRAT_MERCAN_ID")
private int contratoId;
#Column(name = "CATEGORIA_ID")
private int categoriaId;
#Column(name = "CALIDAD_ID")
private int calidadId;
#Column(name = "VALOR")
private double valor;
.... getters/ setters
In this table I wanted to avoid having an Id, three fields are marked as FK in database and first attempts where with #JoinColumn in the three fields. But it does not worked for hibernate.
Anyway, now ContratoCategoriaCalidad is behaving okay as independent entity. But I will need to implement all maintenance, updates, deletes for each case manually... :(
What I really want, (and I think is a better practice) is a cascade when I saveOrUpdate the contract as the other entities do, but I don't find the way to make a List in contrat_mercan table.
This is working perfect for other relationships in same table:
#OneToOne
#JoinColumn(name="CONDICION")
private Condicion condicion;
#OneToMany (cascade = {CascadeType.ALL})
#JoinTable(
name="contrato_mercan_condicion",
joinColumns = #JoinColumn( name="CONTRATO_MERCAN_ID")
,inverseJoinColumns = #JoinColumn( name="CONDICION_ID")
)
private List<Condicion> condiciones;
But all my attempts to map this failed, what i want, is to have in my Java entity contrat_mercan a field like this:
private List<ContratoCategoriaCalidad> relacionContratoCategoriaCalidad;
not a real column in database, just representation of the relationship.
I found solutions to join multiple fields of the same table, here, and here, but not to make a relationship with 3 tables...
Any idea? Im doing something wrong? Maybe i must use intermediate table categoria_calidad to perform this?
Thanks!!
If you want to access a list of related ContratoCategoriaCalidad objects from Contrato entity you need to declare a relationship between those two entities using proper annotations.
In ContratoCategoriaCalidad class change field to:
#ManyToOne
#JoinColumn(name = "CONTRATO_ID")
private Contrato contrato;
In Contrato class add field:
#OneToMany(mappedBy = "contrato")
private List<ContratoCategoriaCalidad> relacionContratoCategoriaCalidad;
If you want to enable cascade updates and removals consider adding cascade = CascadeType.ALL and orphanRemoval = true attributes to #OneToMany annotation.
Hope this helps!
hi I'm getting this "javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: ERROR: duplicate key value violates unique constraint"
I have two tables A and B,
A has id, b_id, B has id,A_id's.
A - oneToMany , B - manyToOne relationship.
on A,
#OneToOne(cascade = { CascadeType.ALL })
#JoinColumn(name = "LATEST_VERSION_ID") #Valid
#EntityProperty(type = "GuidKey", relation = "B.id")
on B,
#ManyToOne(cascade = {CascadeType.ALL})
#JoinColumn(name = "A_ID") #Valid
#EntityProperty(type = "Key", relation = "A.id")
when I create Page A I was able to Do so, But when I try to update I get unique constraint violation on table 'B'.
It says the record already exist.
You have to make a bi-directional relation using the mappedBy property.
See:
one to one bidirectional hibernate mapping
http://www.mkyong.com/hibernate/hibernate-one-to-one-relationship-example-annotation
http://www.codereye.com/2009/04/hibernate-bi-directional-one-to-one.html
Also, #EntityProperty isn't required for this. The foreign key should be in one table in one-to-one.
There are two main #Entity classes reflecting these tables:
TableA {id,name}
TableB {id,name}
And one reference table
TableC {tableA.id,tableB.id}
Question is: how to map a TableA's entity's field with #OneToMany realation to TableB objects list:
#OneToMany
??????????
private List<TableBEntity> tableBItems;
If what you really have is a OneToMany (which means that a give tableB.id appears at most once in TableC), then the mapping is the following:
#OneToMany
#JoinTable(name = "TableC",
joinColumns = #JoinColumn(name = "TABLE_A_ID"),
inverseJoinColumns = #JoinColumn(name = "TABLE_B_ID"))
private List<TableBEntity> tableBItems;
Else, what you have is in fact a ManyToMany, and the mapping is the same, except that #OneToMany must be replaced by #ManyToMany.