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
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
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.
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?
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")`
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.