I'm trying to map a ManyToMany relationships between 2 tables, both having composite primary keys
LSFOCTB which primary key is composed of : LSFOC_CODSOC,LSFOC_CODLSC,LSFOC_CODFOC
LSFORTB which primary key is composed of : LSFOR_CODSOC,LSFOR_CODLSC,LSFOC_CODFOR
The table in charge of the ManyToMany relationship is :
LSFCFTB, with : LSFCF_CODSOC,LSFCF_CODLSC,LSFCF_CODFOC,LSFCF_CODFOR
So, in the hibernate model mapping LSFOCTB, I tried :
#ManyToMany(targetEntity = package.LSFOCTB.class, cascade = { CascadeType.PERSIST,
CascadeType.MERGE })
#JoinTable(name = "LSFCFTB", joinColumns = {
#JoinColumn(name = "LSFCF_CODLSC", referencedColumnName = "LSFOC_CODLSC"),
#JoinColumn(name = "LSFCF_CODFOC", referencedColumnName = "LSFOC_CODFOC"),
#JoinColumn(name = "LSFCF_CODSOC", referencedColumnName = "LSFOC_CODSOC") },
inverseJoinColumns = { #JoinColumn(name = "LSFCF_CODLSC", referencedColumnName = "LSFOR_CODLSC"),
#JoinColumn(name = "LSFCF_CODFOR", referencedColumnName = "LSFOR_CODFOR"),
#JoinColumn(name = "LSFCF_CODSOC", referencedColumnName = "LSFOR_CODSOC") })
before the getter.
But it won't work...
The error, when trying to access the distant collection is :
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in class path resource [beans-dao.xml]: Invocation of init method failed; nested exception is org.hibernate.MappingException: Repeated column in mapping for collection: package.LSFOCTB.distantCollection column: LSFCF_CODLSC
Have already managed to make an hibernate mapping work for a ManyToMany relationship ?
If so, what is wrong with my mapping ?
Thank you for your help !
The problem seems to be that you are creating a join table with 6 columns and there are duplicate names for your columns. You are actually creating 2 columns with the name LSFCF_CODLSC and 2 columns named LSFCF_CODFOR and 2 columns named LSFCF_CODSOC.
I would suggest that you try this:
#JoinTable(name = "LSFCFTB", joinColumns = {
#JoinColumn(name = "LSFOC_LSFCF_CODLSC", referencedColumnName = "LSFOC_CODLSC"),
#JoinColumn(name = "LSFOC_LSFCF_CODFOC", referencedColumnName = "LSFOC_CODFOC"),
#JoinColumn(name = "LSFOC_LSFCF_CODSOC", referencedColumnName = "LSFOC_CODSOC") },
inverseJoinColumns = { #JoinColumn(name = "LSFOR_LSFCF_CODLSC", referencedColumnName = "LSFOR_CODLSC"),
#JoinColumn(name = "LSFOR_LSFCF_CODFOR", referencedColumnName = "LSFOR_CODFOR"),
#JoinColumn(name = "LSFOR_LSFCF_CODSOC", referencedColumnName = "LSFOR_CODSOC") })
or something similar (according to your naming convention) to give each column a unique name.
Related
I am new to Spring Boot. I tried to do an Authentication module where user can Register and Login Based in their role. I have written the logic for user registration and then when I run this it's not running but show me:
Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: Repeated column in mapping for collection: net.osmanforhad.main.model.User.roles column: user_id
here is the many to many relation code:
#Column(name = "roles")
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(
name = "users_roles",
joinColumns = #JoinColumn(
name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(
name = "user_id", referencedColumnName = "id"
)
)
private Collection<Role> roles;
is there any one to suggest me how i should fix this issue
.
Thanks in advance
I have the following 3 tables
table: project
id
company_code
number
contract_type_code
account_type_code
other columns…
table: contract_type
id
company_code
code
name
table: account_type
id
company_code
code
name
The project table references contract_type and account_type tables through contract_type_code/company_code and account_type_code/company_code respectively.
The company_code and code columns are what make a contract_type and account_type unique.
I'm struggling with modelling and mapping this in JPA. I've tried with the #JoinColumn and #JoinColumns annotation and there's no way for me to make it work.
This is one of the ways I've been trying with no success:
public class Project implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long companyCode;
private Long number;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumns({
#JoinColumn(name = "contract_type_code", referencedColumnName = "code"),
#JoinColumn(name = "company_code", referencedColumnName = "company_code")
})
private ContractType contractType;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumns({
#JoinColumn(name = "account_type_code", referencedColumnName = "code"),
#JoinColumn(name = "company_code", referencedColumnName = "company_code")
})
private AccountType accountType;
This is the issue I'm getting with the mapping above:
Caused by: org.hibernate.MappingException: Unable to find column with logical name company_code in table contract_type
For this mapping:
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumns({
#JoinColumn(name = "contract_type_code", referencedColumnName = "code", insertable = false, updatable = false),
#JoinColumn(name = "company_code", referencedColumnName = "company_code2", insertable = false, updatable = false)
})
private ContractType contractType;
I get:
Caused by: org.hibernate.DuplicateMappingException: Table [account] contains physical column name [company_code] referred to by multiple logical column names: [company_code], [companyCode]
I assume you have companyCode fields in the AccountType and ContractType. Annotate them as below (first error suggests JPA can't find them):
#Column(name = "company_code")
In your Project class modify companyCode field as follows (to avoid the second error):
#Column(name = "company")
private Long companyCode;
and keep mapping with:
insertable = false, updatable = false
Hope this will help. If not please add AccountType and ContractType classes to your question. Maybe then it will be easier to sort it out
DB tables (not quite SQL but you get the gist..)
definition (
id int, -- PK
type int,
label varchar(20) -- definition label can change over time
)
asset (
id int, -- PK
-- other asset fields...
)
property (
id int, -- PK
asset_id int, -- with FK to asset + on delete cascade
definition_id int, -- with FK to definition + on delete cascade
payload varchar(256)
)
A map of the definition id int to payload (Map<int,String>), like this below, works but that's not what I want.
[Asset class]
#ElementCollection
#CollectionTable(name = "properties",
joinColumns = {#JoinColumn(name = "asset_id", referencedColumnName = "id")})
#MapKeyColumn(name = "definition_id")
#Column(name = "payload")
Map<Integer,String> properties;
Instead, I'm trying to have the following map in my Asset class:
Map<Definition,String> properties;
but can't figure what to do. The #MapKeyJoinColumn annotation is intended to pull a relation out of the a entity-type map value so I cannot complete this below:
#OneToMany(cascade = CascadeType.ALL)
#JoinTable(name = "properties",
joinColumns = {#JoinColumn(name = "asset_id", referencedColumnName = "id")},
//inexistant - inverseJoinColumns = {#JoinColumn(name = "property_id", referencedColumnName = "id")})
#MapKeyJoinColumn(name = "definition_id")
Map<Definition,String> properties;
I want a value-type map value. My 'properties' table has the definition_id so I really just need jpa/hibernate to join a table for the entity key, not the value.
Any clue?
From a commenter, this works:
[Asset class]
#ElementCollection
#CollectionTable(name = "properties",
joinColumns = {#JoinColumn(name = "asset_id", referencedColumnName = "id")})
#MapKeyJoinColumn(name = "definition_id")
#Column(name = "payload")
Map<Definition,String> properties;
The non-intuitive answer was to force #MapKeyJoinColumn and the key Entity type, regardless of the #ElementCollection presence.
I have no idea if this is just a fluke with hibernate abilities, or if it is actually supported by JPA.
I have 2 entities - User and Role which have following relations: User has a manytomany relation to itself and a manytomany relation with the Role entity.
#Entity
public class UserEntity implements Serializable {
#Id
#Column(length = 12, columnDefinition = "BINARY(12)", name = "Id", unique = true)
private byte[] id;
#Column(name = "Login", unique = true, nullable = false)
private String login;
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "User_Role",
joinColumns = { #JoinColumn(name = "UserLogin", referencedColumnName = "Login") },
inverseJoinColumns = { #JoinColumn(name = "RoleId", referencedColumnName = "Id") })
private Set<RoleEntity> roles;
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name = "User_User",
joinColumns = { #JoinColumn(name = "UserParent") },
inverseJoinColumns = { #JoinColumn(name = "UserChild") })
private Collection<UserEntity> children;
...
}
and Role:
public class RoleEntity implements Serializable{
#Id
#Column(name = "Id", unique = true, nullable = false)
private String id;
...
}
The strange thing about the setup of DB is that the User_User relation is based on the binary Id keys
create table if not exists User_User (
UserParent binary,
UserChild binary
);
and the user-role is based on varchars
create table if not exists KNUser_UserRole (
UserLogin varchar,
RoleId varchar,
);
Now, when it runs, the user-user relationship work well. However, when I try to access the collection returned for roles, I get a ClassCastException:
java.lang.ClassCastException: **.entity.UserEntity cannot be cast to [B
at org.hibernate.type.descriptor.java.PrimitiveByteArrayTypeDescriptor.extractHashCode(PrimitiveByteArrayTypeDescriptor.java:41)
at org.hibernate.type.AbstractStandardBasicType.getHashCode(AbstractStandardBasicType.java:201)
at org.hibernate.type.AbstractStandardBasicType.getHashCode(AbstractStandardBasicType.java:205)
at org.hibernate.engine.spi.EntityKey.generateHashCode(EntityKey.java:114)
at org.hibernate.engine.spi.EntityKey.<init>(EntityKey.java:79)
at org.hibernate.internal.AbstractSessionImpl.generateEntityKey(AbstractSessionImpl.java:240)
at org.hibernate.engine.internal.StatefulPersistenceContext.getCollectionOwner(StatefulPersistenceContext.java:740)
at org.hibernate.loader.Loader.readCollectionElement(Loader.java:1181)
at org.hibernate.loader.Loader.readCollectionElements(Loader.java:800)
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:651)
at org.hibernate.loader.Loader.doQuery(Loader.java:856)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:289)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259)
at org.hibernate.loader.Loader.loadCollection(Loader.java:2175)
at org.hibernate.loader.collection.CollectionLoader.initialize(CollectionLoader.java:61)
at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:622)
at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:82)
at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:1606)
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:379)
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:112)
at org.hibernate.collection.internal.PersistentSet.iterator(PersistentSet.java:180)
It looks like the UserEntity is being cast to some binary(?) thing. However, the first relation between users themselves works fine, but the one with another table is wrong.
I am using different columns of different types to join tables. Is it allowed to do it this way?
Another strange thing is that when I switch the #Id annotation to be on the login field, the roles work fine, no issue, but then of course the self-join PersistentBag key is the Login instead of Id, which breaks the relation and no results are retrieved. But the conversion from UserEntity to the "[B" is not done.
Also if I leave things as in example and change the Id type to String (and the DB to varchar) it also starts working (of course not consistently with the User_User table).
What am I doing wrong? What is the reason for getting the classcastexception in this case? Why it work when I change the byte[] to String? Please let me know if you have any ideas. I do not want to change the DB design cause this would lead to lots migration and compatibility issues for clients already using the DB.
Just a note: the #Id has to be on the Id binary field as otherwise I wouldn't be able to make a self-join (I was unable to point twice to a column not being a primary key see: Is Hibernate ManyToMany self-join possible for non-key columns? getting mappingException).
Cheers
Adam
the referred column in your join table must be unique entry, here if you put #Id on login field then it works fine,but when you change it to different other than #Id column you cant be sure about the entries will be unique.what you can do is,
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "User_Role",
joinColumns = { #JoinColumn(name = "UserLogin", referencedColumnName = "Id") },
inverseJoinColumns = { #JoinColumn(name = "RoleId", referencedColumnName = "Id") })
private Set<RoleEntity> roles;
I think it should work.
I have quite big problem with hibernate annotation mapping. Heres my diagram:
As for mapping object, few are simple cause its 1...N for:
TASK_DEF -> REPORT_DATA
REPORT_DATA -> REPORT_DATA_COLUMN
REPORT_DATA -> REPORT_DATA_VALUE
right?
Now problem is when I'm trying to map Collection of REPORT_DATA_VALUE to REPORT_DATA_COLUMN. I've tried this way:
#OneToMany(fetch = FetchType.LAZY)
#ForeignKey(name = "FK_REPORT_DATA_VALUE_REPORT_DA", inverseName = "PK_REPORT_DATA_COLUMN")
#JoinTable(name = "REPORT_DATA_VALUE", joinColumns = {
#JoinColumn(name = "REPORT_DATA_ID"),
#JoinColumn(name = "COLUMN_NM")
}, inverseJoinColumns = {
#JoinColumn(name = "REPORT_DATA_ID"),
#JoinColumn(name = "COLUMN_NM")
})
List<ReportDataValue> reportDataValueList;
But hibernate selects wrong identifies, therefore couldnt execute query. Could someone help me with this?
There is a problem in your code. Try this instead:
#OneToMany(fetch = FetchType.LAZY)
#JoinTable(name = "REPORT_DATA_VALUE", joinColumns = {
#JoinColumn(name = "REPORT_DATA_ID"),
}, inverseJoinColumns = {
#JoinColumn(name = "COLUMN_NM")
})
List<ReportDataValue> reportDataValueList;
By the way, If I were you, I wouldn't create a table for One To Many. I'd do this:
public class A{
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="B_ID")
B b;
}
public class B{
#OneToMany(mappedBy="b",fetch=FetchType.EAGER)
Set<A> as;
}