Hibernate many-to-many mapping referencing partial composite key - java

My problem is like this one: https://forum.hibernate.org/viewtopic.php?f=1&t=1002125
I have the following tables in my schema:
a table A with a composite key (attr1, attr2);
a table B with a pk (attr3);
and a table A_B which is a relationship table between A and B with a composite key (fk_attr1, fk_attr3), where fk_attr1 and fk_attr3 references the fields attr1 and attr2, respectively
The attr2 is not used in the relationship.
I generated the mapping java classes with hibernate plugin, and the generated code looks like this:
class A
private Set<B> bs = new HashSet<B>(0);
private AId id;
#EmbeddedId
#AttributeOverrides({ #AttributeOverride(name = "attr1", column = #Column(name = "attr1", nullable = false)),
#AttributeOverride(name = "attr2", column = #Column(name = "attr2", nullable = false)) })
public AId getId() {
return this.id;
}
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "A_B", catalog = "my_schema", joinColumns = { #JoinColumn(name = "fk_attr1", nullable = false, updatable = false) }, inverseJoinColumns = { #JoinColumn(name = "fk_attr3", nullable = false, updatable = false) })
public Set<B> getBs() {
return this.bs;
}
class B
private Set<A> as = new HashSet<A>(0);
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "A_B", catalog = "my_schema", joinColumns = { #JoinColumn(name = "fk_attr3", nullable = false, updatable = false) }, inverseJoinColumns = { #JoinColumn(name = "fk_attr1", nullable = false, updatable = false) })
public Set<A> getAs() {
return this.as;
}
class AId (the id for entity A)
private String attr1;
private Long attr2;
#Column(name = "attr1", nullable = false)
public String getAttr1() {
return this.attr1;
}
#Column(name = "attr2", nullable = false)
public Long getAttr2() {
return this.attr2;
}
But it always generates this exception:
org.hibernate.AnnotationException: A Foreign key refering A from B has the wrong number of column. should be 2
What is the right way to accomplish this relationship with Hibernate?

Related

"Select all Documents from one content" hibernate relationship many to many

I have tow models:
#Entity
public class Documento implements java.io.Serializable {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private Integer id;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "appc_contenido_documento", catalog = "appcope",
joinColumns = {
#JoinColumn(name = "id_documento", nullable = false, updatable =
false)}, inverseJoinColumns = {
#JoinColumn(name = "id_contenido", nullable = false, updatable =
false)})
private Set<Contenido> contenidos = new HashSet<Contenido>(0);
}
and
#Entity
public class Contenido implements java.io.Serializable {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private Integer id;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "appc_contenido_documento", catalog = "appcope",
joinColumns = {
#JoinColumn(name = "id_contenido", nullable = false, updatable =
false)}, inverseJoinColumns = {
#JoinColumn(name = "id_documento", nullable = false, updatable =
false)})
private Set<Documento> documentos = new HashSet<Documento>(0);
}
I donĀ“t find an example this, only I find examples with relationship one to many
How can I select all the documents of a content with CriteriaQuery?
It is usually a good idea to reduce your many to many relationship to one to many. This usually can be done by introducing a bridging entity. It maybe worth adding such a table here.

Illegal attempt to map a non collection as a #OneToMany, #ManyToMany or #CollectionOfElements

I have one lawyer table which is having id(int) as a primary key and Country table having country_code(String ) as a primary key. I want to create third table using #JoinTable annotation in hibernate with two foreign key in it. But when I run it following error is coming. Not sure how to map one string and one int as foreign keys in third table.
Illegal attempt to map a non collection as a #OneToMany, #ManyToMany or #CollectionOfElements: com.test.common.entities.Country.lawyer
This is my code
#Entity
#Table(name = "lawyer")
public class Lawyer {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "lawyer_batch_no")
private int lawyerbatchNo;
#ManyToOne(targetEntity = Country.class, cascade = { CascadeType.ALL })
#JoinTable(name = "lawyer_cscd", joinColumns = {
#JoinColumn(name = "lawyer_batch_no", referencedColumnName = "lawyer_batch_no") }, inverseJoinColumns = {
#JoinColumn(name = "country_code", referencedColumnName = "country_code") })
private Country country;
getter setter...
}
#Entity
#Table(name = "country")
public class Country {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "country_code")
protected String country_code;
#Column(name = "abbreviation")
protected String abbreviation;
#Column(name = "name", nullable = false)
protected String name;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "country")
protected Set<State> state = new HashSet<State>();
#OneToMany(targetEntity = Lawyer.class, cascade = { CascadeType.ALL }, orphanRemoval = true)
#JoinTable(name = "lawyer_cscd", joinColumns = {
#JoinColumn(name = "country_code", referencedColumnName = "country_code") }, inverseJoinColumns = {
#JoinColumn(name = "lawyer_batch_no", referencedColumnName = "lawyer_batch_no") })
private Lawyer lawyer;
getter setter....
}
The error indicates that private Lawyer lawyer needs to be a collection as it's a #OneToMany relationship. In the Country class, the last relationship should be
#OneToMany(targetEntity = Lawyer.class, cascade = { CascadeType.ALL }, orphanRemoval = true)
#JoinTable(name = "lawyer_cscd", joinColumns = {
#JoinColumn(name = "country_code", referencedColumnName = "country_code") }, inverseJoinColumns = {
#JoinColumn(name = "lawyer_batch_no", referencedColumnName = "lawyer_batch_no") })
private Set<Lawyer> lawyer;
// or a Collection/List/etc.

Unidirectional OneToMany with Composite Primary key not persisted

I have an ER relationship from a legacy DB (MS SQL Server based as below
The way that I'm currently trying to convert this to the JPA 2.1 style is as below
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public class Orders implements Serializable {
#Id
#GeneratedValue
#Column(name = "OrderNumber", nullable = false)
private Integer orderNumber;
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(
name = "OrderHistory",
joinColumns = {
#JoinColumn(name = "OrderNumber", referencedColumnName = "OrderNumber", nullable = false)
}
)
private List<OrderHistory> orderHistory;
----Other properties, Getters and Setters
}
#Entity
#PrimaryKeyJoinColumn(name = "OrderNumber")
public class SpecialOrders extends Orders implements Serializable {
#JoinColumn(name = "OrderNumber", referencedColumnName = "OrderNumber", nullable = false)
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
#Fetch(FetchMode.SELECT)
#OrderBy("sequenceNumber ASC")
private List<Items> items;
----Other properties, Getters and Setters
}
#Entity
#IdClass(ItemsPK.class)
public class Items implements Serializable {
#Id
#Column(name = "OrderNumber", nullable = false, insertable = false, updatable = false)
private Integer orderNumber;
#Id
#Column(name = "SequenceNumber", nullable = false)
private Integer sequenceNumber;
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(
name = "CustomOptions",
joinColumns = {
#JoinColumn(name = "OrderNumber", referencedColumnName = "OrderNumber", nullable = false),
#JoinColumn(name = "SequenceNumber", referencedColumnName = "SequenceNumber", nullable = false)
}
)
private List<CustomOptions> customOptions;
----Other properties, Getters and Setters
}
#Entity
public class ItemsPK implements Serializable {
#Id
#Column(name = "OrderNumber", nullable = false, insertable = false, updatable = false)
private Integer orderNumber;
#Id
#Column(name = "SequenceNumber", nullable = false)
private Integer sequenceNumber;
----Getters and Setters
}
#Entity
#IdClass(CustomOptionsPK.class)
public class CustomOptions implements Serializable {
#Id
#Column(name = "OrderNumber", nullable = false, insertable = false, updatable = false)
private Integer orderNumber;
#Id
#Column(name = "SequenceNumber", nullable = false)
private Integer sequenceNumber;
#Id
#Column(name = "OptionNumber", nullable = false)
private Integer optionNumber;
----Other properties, Getters and Setters
}
public class CustomOptionsPK implements Serializable {
#Id
#Column(name = "OrderNumber", nullable = false, insertable = false, updatable = false)
private Integer orderNumber;
#Id
#Column(name = "SequenceNumber", nullable = false)
private Integer sequenceNumber;
#Id
#Column(name = "OptionNumber", nullable = false)
private Integer optionNumber;
----Getters and Setters
}
With the above code, I see that hibernate does below
INSERTs into Orders and gets the GeneratedId for OrderNumber
INSERTs into SpecialOrders, using the orderNumber retrieved above.
Attemps to INSERT into Items table, with a NULL value in the orderNumber and then fails because the orderNumber is a NOT NULL column.
Subsequently, If add a "Simple" primary key to Items table and make the orderNumber as a NULLable column, then the below happens:
INSERTs into Orders and gets the GeneratedId for OrderNumber
INSERTs into SpecialOrders, using the orderNumber retrieved above.
INSERTs into Items table with orderNumber as NULL value and gets the generated id of the Items table row.
Updates the row of Items table with the orderNumber from parent, using the retrieved id for Items.
Attemps to INSERT into CustomOptions table, with a NULL value in the orderNumber and then fails because the orderNumber is a NOT NULL column.
As per the above sequence, it seems that:
Composite Primary key doesnt seem to be working correctly or not supported.
Hibernate is handling the OneToMany relationship inefficiently by issuing an INSERT followed by an UPDATE, instead of just an insert.
Any idea if my understanding is correct? The only way of fixing this issue seems to be that I need to remove the composite primary key and replace it with a simple one.

Hibernate criteria cannot retrieve values of a join

I have following entities and need to retrieve a list of names of all stores that are in a specific group and have branches in a specific city. Majority of tutorials and articles that Ive found are related to creating this type of relationships but none of them is about retrieval!
I changed the criteria for many times but Hibernate shows different errors for each. The commented parts of the code are those that I tried and the respective thrown exception is also written in front of each.
Entities
#Entity
public class Store {
#Id
String id;
String name;
#JoinTable(name = "store_groups", joinColumns = { #JoinColumn(name = "id", nullable = false, updatable = false) }, inverseJoinColumns = { #JoinColumn(name = "code", nullable = false, updatable = false) })
private Set<Group> groups = new HashSet<Group>(0);
private Set<StoreAddress> storeAddresses = new HashSet<StoreAddress>(0);
....
}
#Entity
public class Group {
#Id
String code;
#Column(nullable = false, unique = true)
String name;
#ManyToMany(fetch = FetchType.LAZY, mappedBy = "groups")
Set<Store> storees = new HashSet<Store>(0);
}
#Entity
#Table(name = "StoreAddresses")
#AssociationOverrides({
#AssociationOverride(name = "muJoinTable.store", joinColumns = #JoinColumn(name = "id", nullable = false)),
#AssociationOverride(name = "myJoinTable.city", joinColumns = #JoinColumn(name = "cityCode", nullable = false)) })
public class StoreAddress {
#EmbeddedId
private StoreCitysId myJoinTable = new StoreCitysId();
...
}
#Embeddable
public class StoreCitysId {
#ManyToOne
private Store store;
#ManyToOne
private City city;
}
#Entity
public class City {
#Id
short code;
#Column(nullable = false)
String name;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "myJoinTable.city")
private Set<StoreAddress> storeAddresses = new HashSet<StoreAddress>(
0);
}
Criteria
List<String> storees = (List<String>) sessionFactory
.getCurrentSession()
.createCriteria(Store.class)
.setProjection(
Projections.property("name").as(
"storeName"))
.createAlias("groups", "group")
.createAlias("storeAddresses", "address")
// .createAlias("address.myJoinTable.city", "city")
// .createAlias("address.myJoinTable", "myJoinTable")
// .createAlias("myJoinTable.city", "city") Error: Criteria objects cannot be created directly on components
.setFetchMode("group", FetchMode.JOIN)
.add(Restrictions.ilike("group.code", store))
.add(Restrictions.eq("address.myJoinTable.cityCode",
1)).list(); //city.code -> Error: could not resolve property: cityCode of:com.example.entity.StoreAddress address.myJoinTable.cityCode could not resolve property: myJoinTable.cityCode of:com.example.entity.StoreAddress
Your criterion Restrictions.eq("address.myJoinTable.cityCode", 1) doesn't reference a property but the name of the column. You could instead use address.myJoinTable.city and set the value to session.load(City.class, 1) making Restrictions.eq("address.myJoinTable.city", session.load(City.class, 1))
And this:
.createAlias("address.myJoinTable", "myJoinTable")
.createAlias("myJoinTable.city", "city")
Should be:
.createAlias("address.myJoinTable.city", "city")

JPA/EclipseLink - Undesirable Foreign Key created during table create/update on startup

I have the following #Entity classes
#Entity
public class Asset {
#Id
private long id;
#Enumerated(EnumType.STRING)
private TagType tagType;
private String tagId;
#OneToOne(cascade = CascadeType.ALL, optional = true, orphanRemoval = true)
#JoinColumns(value = {
#JoinColumn(name = "tagId", referencedColumnName = "tagId", nullable = true, insertable = false, updatable = false),
#JoinColumn(name = "tagType", referencedColumnName = "tagType", nullable = true, insertable = false, updatable = false)})
private TagInfo tagInfo;
...
}
and
#Entity
public class TagInfo {
#Id
private String tagId
#Id
private TagType tagType
...
}
When EclipseLink start using "eclipselink.ddl-generation" = "drop-and-create-tables", it creates the ASSET table with the following constraint:
CONSTRAINT FK_ASSET_TAGTYPE FOREIGN KEY(TAGTYPE,TAGID) REFERENCES TAGINFO(TAGTYPE,TAGID))
Is there anyway to have EclipseLink NOT create the above constraint on the Asset table?

Categories