hibernate - how to JoinColumn an EmbeddedId - java

Situation: I have a masterDB and a library1DB and library2DB.
library1DB and library2DB are two separate database but has the same schema because each library must have their own database. Now we have a masterDB, this is an aggregated version of all the data in all libraries (library1DB and library2DB), still taking note of their respective ids and mapping them to their library id.
Here's I want my tables to be structured:
book
- book_id
- library_id
- title
- shelf_id
shelf
- shelf_id
- library_id
- book_id
- description
I have these models:
#Entity
public class Book {
#EmbeddedId
private BookKey bookKey;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumns({
#JoinColumn(name = "SHELF_ID", referencedColumnName = "SHELF_ID"),
#JoinColumn(name = "LIBRARY_ID", referencedColumnName = "LIBRARY_ID")
})
private ObjectA objectA;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumns({
#JoinColumn(name = "ANOTHER_ID", referencedColumnName = "ANOTHER_ID"),
#JoinColumn(name = "LIBRARY_ID", referencedColumnName = "LIBRARY_ID")
})
private ObjectB objectB;
#Column
private String title;
}
#Embeddable
public class BookKey implements Serializable {
#Column(name = "BOOK_ID")
private long bookId;
#Column(name = "LIBRARY_ID")
private long libraryId;
}
But I get this exception:
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: Book column: library_id (should be mapped with insert="false" update="false")
I've tried using #IdClass instead of #Embeddable and #EmbeddedId, and I got this:
Caused by: org.hibernate.DuplicateMappingException: Table [book] contains physical column name [libraryId] represented by different logical column names: [libraryId], [LIBRARY_ID]
Any help?
Thanks!

You should add insert="false", update="false" for the second mapped column library_id.
Try this:
#JoinColumn(name = "LIBRARY_ID", referencedColumnName = "LIBRARY_ID",
insertable = false, updatable = false)

I was getting the same problem. If you add insert="false", update="false" only to one, you will get an exception stating that you mixed writable and non-writables and that this is not allowed. The following works:
I solved it using the #PrimaryKeyJoinColumns, try this (from another example):
#ManyToOne
#PrimaryKeyJoinColumns(value = {
#PrimaryKeyJoinColumn(name = "country_code", referencedColumnName = "country_code"),
#PrimaryKeyJoinColumn(name = "zip_code", referencedColumnName = "code")
})
private Zip zip;
#ManyToOne
#PrimaryKeyJoinColumns(value = {
#PrimaryKeyJoinColumn(name = "country_code", referencedColumnName = "country_code"),
#PrimaryKeyJoinColumn(name = "state_code", referencedColumnName = "state_code"),
#PrimaryKeyJoinColumn(name = "city_name", referencedColumnName = "name")
})
private City city;
from Hibernate throws AnnotationException on column used by multiple overlapping foreign keys

Related

Mapping two columns in JPA

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

Could not execute SQL statement

While writing my application I came across a problem with executting SQL statement. I tried to look for a solution on the net, but none of the found helped and I still do not know how to deal with an error I get. Here is exception I get:
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint ["FKAM8LLDERP40MVBBWCEQPU6L2S: PUBLIC.BOOK_CATEGORY FOREIGN KEY(CATEGORY_ID) REFERENCES PUBLIC.CATEGORY(ID) (2)"; SQL statement:
insert into book_category (book_id, category_id) values (?, ?) [23506-196]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
And this is how the classes looks:
Book.class
#Entity
#Table(name = "book")
public class Book {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(nullable = false)
private String title;
private String description;
#Column(name = "release_date")
#Temporal(TemporalType.TIMESTAMP)
private Date releaseDate;
#JoinColumn(name = "cover_image")
#OneToOne(cascade = CascadeType.MERGE)
private UploadFile coverImage;
#OneToOne(cascade = CascadeType.MERGE)
private UploadFile content;
#ManyToMany
#JoinTable(name = "book_category", joinColumns = {#JoinColumn(name = "book_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "category_id", referencedColumnName = "id")})
private Set<Category> categories;
// constructors, setters, getters
}
Category.class
#Entity
#Table(name = "category")
public class Category {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "category_name")
private String name;
#ManyToMany(mappedBy = "categories", fetch = FetchType.LAZY)
private List<Book> books;
// ...
}
Your are missing cascade definitions there.
Your Book Category gets written before a referenced entity (book or category) gets inserted first. This is not allowed due to the constraint you specified. The solution is to define
cascade = CascadeType.ALL
On both sides of the join (both in books and in categories). This is going to ensure that JPA persists all entities in the right order.

Is it possible to implement (0..n) many to many (using #ManyToMany annotation) relation in JPA?

I'm looking for a way to implement (0..n) many to many relation in JPA, much possibly using #ManyToMany annotation. All examples that I found were about (1..n) relations. What I need to accomplish:
- I've got two entities: Contact and Tag. Each Contact can have 0..n Tags. Each Tag can have 0..n Contacts. From SQL point of view it would look like
this: Contact (0..n) --- (1) Contact_has_Tag (1) --- (0..n) Tag.
Code below is not working for me because JPA is linking columns with INNER JOIN.
OFC I could do this using intermediate entity and #OneToMany and #ManyToOne annotations, but I want a simpler sollution.
#Data
#Entity
public class Contact {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#JsonIgnore
private long id;
#Column(unique = true)
private String email;
// ...
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JsonIgnore
#JoinTable(
name = "contact_has_tag",
joinColumns = #JoinColumn(name = "contact_id", referencedColumnName = "id", updatable = false, nullable = true),
inverseJoinColumns = #JoinColumn(name = "tag_id", referencedColumnName = "id", updatable = false, nullable = true))
private List<ContactTag> contactTags = new ArrayList<ContactTag>();
}
#Entity
#Data
public class ContactTag {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column
private String name;
#ManyToMany(mappedBy="contactTags", fetch = FetchType.LAZY)
#JsonIgnore
private List<Contact> contacts = new ArrayList<Contact>();
}
Any ideas how it should be done?

com.microsoft.sqlserver.jdbc.SQLServerException: Invalid column name 'xxx'

Entity class 1
#Entity
#Table(name = "TICKETS")
public class Ticket {
....
#Column(name = "MERCHANT_NBR")
private String merchant_nbr;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "merchant_nbr", nullable = false)
private Merchant merchant;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name ="merchantNBR", nullable = false)
private merchantDetails merchantDetails;
Entity class 2
#Entity
#Table(name="MERCHANT_DETAILS")
public class merchantDetails {
#Id
#Column(name="MERCHANT_NBR")
private String merchantNBR;
#OneToMany(fetch = FetchType.LAZY)
private Set<Ticket> ticket;
error its giving...invalid column 'merchantNBR'.But I have a column by that name.
com.microsoft.sqlserver.jdbc.SQLServerException: Invalid column name 'merchantNBR'.
so it's a join column not a column and for that you have to use the proper annotation for joining two entities which is #JoinColumn
see this it may be helpful
#joinColumn(name = "MERCHANT_NBR" ,referencedColumnName="merchantNBR")
private String merchant_nbr;
here i supposed that you've changed the column name in entitie class 2 from
#Column(name="MERCHANT_NBR") to `#Column(name="merchantNBR")`

JPA Mapping of Association table where one of the entities has composite key

I have the following model that I need to annotate using JPA:
Merchant(merchant_id, ...).
MerchantType(id1, id2, ...)
MerchantMerchantTypeAssociationTable(merchant_id, id1, id2)
I cannot figure out how to map the association table. Mapping Merchant is straitghtforward, so I will leave it outside of the mappings. The other mappings are as follows:
MerchantType:
#Entity
class MerchantType {
#EmbeddedId
#AttributeOverrides({
#AttributeOverride(name = "e1_id", column=#Column(name="e1_id")),
#AttributeOverride(name = "another_id", column=#Column(name="another_id"))
})
MerchantTypePk id;
#ManyToOne
#JoinColumn(name = "e1_id", referencedColumnName = "e1_id", insertable = false, nullable = false)
#MapsId("e1_id")
AnotherEntity1 e1;
#Column(name = "another_id", referencedColumnName = "another_id", insertable = false, nullable = false)
Long anotherId;
//Two other local fields irrelevant to the discussion here
public MerchantType(){
this.id = new MerchantTypePk();
}
//Getters and setters here.
}
//MerchantTypePk is a simple Embeddable class here below with two Long fields:
//e1_id and another_id
MerchantMerchantTypeAssociation:
#Entity
class MerchantMerchantTypeAssociation {
#EmbeddedId
#AttributeOverrides({
#AttributeOverride(name = "e1_id", column = #Column(name = "e1_id")),
#AttributeOverride(name = "another_id", column = #Column(name = "another_id"))
#AttributeOverride(name = "offer_id", column = #Column(name = "merchant_id"))
})
private MerchantMerchantTypeAssociationPk id;
//******** HERE IS THE QUESTION
//******** HERE IS THE QUESTION
//******** HERE IS THE QUESTION
#ManyToOne
#JoinColumns({
#JoinColumn(name = "e1_id", referencedColumnName = "e1_id", insertable = false, updatable = false),
#JoinColumn(name = "another_id", referencedColumnName = "another_id", insertable = false, updatable = false)
})
#MapsId("e1_id")
#MapsId("another_id")
private MerchantType merchantType;
//Similar mapping to the one above, but with only one Join Column
private Merchant merchant;
//One more local field that is irrelevant to the mapping
//but is the one that is forcing me to map a many - to - many relationship
//in this way.
}
//MerchantMerchantTypeAssociationPk as a simple embeddable
Question: How can I make a mapping for this kind of entities when the annotation '#MapsId' cannot be repeated and it does not accept more than one value?
You did not include the code for MerchantMerchantTypeAssociationPk, but I'm guessing it looks like this:
#Embeddable
public class MerchantMerchantTypeAssociationPk {
public MerchantPk merchantPK;
public MerchantTypePk merchantTypePK;
}
#MapsId is used to specify the attribute within the composite key to which the relationship attribute corresponds, not the columns. So MerchantMerchantTypeAssociation should look like this:
#Entity class MerchantMerchantTypeAssociation {
#EmbeddedId
private MerchantMerchantTypeAssociationPk id;
#ManyToOne
#JoinColumns({
#JoinColumn(name = "e1_id", referencedColumnName = "e1_id",...),
#JoinColumn(name = "e2_id", referencedColumnName = "e2_id",...)
})
#MapsId("merchantTypePK") // <<< *attribute* in Embeddable
private MerchantType merchantType;
#ManyToOne
#JoinColumn(name = "m_id", referencedColumnName = "merchant_id",...)
#MapsId("merchantPK") // <<< *attribute* in Embeddable
private Merchant merchant;
}
Derived identities are discussed in the JPA 2.1 spec, section 2.4.1.

Categories

Resources