Hibernate mapping entity with a Set of itself - java

I have this class in my code
#Entity(name = "Point")
#Table(name = "Point")
public class Point extends com.lsikh.unlmaps.base.Entity<Integer>{
private Integer id;
...
...
private Set<Point> connections = new HashSet<Point >();
I need to relate a Point entity with many other Point's object in that Set and retrieve.
This are my tables in the database
CREATE
TABLE Point(
id INTEGER UNIQUE AUTO_INCREMENT NOT NULL,
...
...
PRIMARY KEY (id )
);
CREATE
TABLE Connections(
idA INTEGER NOT NULL,
idB INTEGER NOT NULL,
FOREIGN KEY (idA ) REFERENCES Point (id),
FOREIGN KEY (idB ) REFERENCES Point(id)
);
Which is the correct set of hibernate notations to do this.
I think could be
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(name = "Connections", joinColumns = {
#JoinColumn(name = "id") }, inverseJoinColumns = {
#JoinColumn(name = "idA") })
public Set<Point> getConnections() {
return connections;
}
But I'm having problems to do the map and I'm not sure.

According to the javadoc the joinColumns:
The foreign key columns of the join table which reference the primary
table of the entity owning the association
So assuming that idA is the id of the owning entity in the join table the mapping should be:
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(name = "Connections", joinColumns = {
#JoinColumn(name = "idA") }, inverseJoinColumns = {
#JoinColumn(name = "idB") })
public Set<Point> getConnections() {
return connections;
}

Related

Java: Repeated column in mapping for collection

I am trying to create a OneToMany mapping with a LinkedHashMap for my main entity B, that contains the entities VC and P, but I am getting the following error:
Repeated column in mapping for collection:
com.test.model.B.pricing column: b_name
I could be wrong, but I believe that it has something to do with the #JoinColumns or #MapKeyJoinColumn annotation, as I have not done anything like this before, so I am quite sure that I am doing this part incorrectly.
My goal is that I should be able to provide the three fields:
b_name pc and c_id e.g. the VC/VCId
in order to get the a and d_a e.g. P.
Also, if there is a better way to structure things, then I am all ears, as I personally do not really like how I have set up my tables tbh (would be nice if I could just have the b and b_p tables, where the b_p could just have all five fields (key and value) from the p map).
Here is my main entity
#Setter
#Getter
#Entity
#Table(name = "b")
public class B implements Serializable {
#Id
#Column(nullable = false)
private String name;
#OneToMany(cascade = CascadeType.PERSIST)
#JoinTable(
name = "b_p",
joinColumns = #JoinColumn(name = "b_name", referencedColumnName = "name"))
#MapKeyJoinColumns({
#MapKeyJoinColumn(name = "b_name"),
#MapKeyJoinColumn(name = "p_c"),
#MapKeyJoinColumn(name = "c_id")
})
private Map<VC, Price> pricing = new LinkedHashMap<>();
...
}
The Key to the map
#Setter
#Getter
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "v_c")
public class VC implements Serializable {
#EmbeddedId private VCId vcId;
}
The key's PK/Composite Key
#Setter
#Getter
#NoArgsConstructor
#AllArgsConstructor
#Embeddable
public class VCId implements Serializable {
#Column(name = "b_name")
private String bName;
#Column(name = "p_c")
private SomeEnum pc;
#Column(name = "c_id")
private String cId;
}
The value for the map
#Setter
#Getter
#NoArgsConstructor
#Embeddable
#Entity
#Table(name = "price")
public class Price implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long id;
#Column(name = "amount")
private BigDecimal amount;
#Column(name = "discount_amount")
private BigDecimal discountAmount;
}
DB tables
CREATE TABLE b
(
name VARCHAR(100) NOT NULL PRIMARY KEY
...
);
CREATE TABLE v_c
(
bundle_name VARCHAR(100) NOT NULL,
physical_currency TEXT NOT NULL,
coin_id VARCHAR(50) NOT NULL,
FOREIGN KEY (b_name) REFERENCES b (name) ON DELETE CASCADE,
PRIMARY KEY (b_name, p_c, c_id)
);
CREATE TABLE p
(
id BIGSERIAL NOT NULL PRIMARY KEY,
amount NUMERIC,
discount_amount NUMERIC DEFAULT 0.00
);
CREATE TABLE b_p
(
bname VARCHAR(100) NOT NULL,
p_c TEXT NOT NULL,
c_id VARCHAR(50) NOT NULL,
price_id BIGSERIAL NOT NULL,
FOREIGN KEY (b_name, p_c, c_id) REFERENCES v_c (b_name, p_c, c_id) ON DELETE CASCADE,
FOREIGN KEY (price_id) REFERENCES price (id) ON DELETE CASCADE,
PRIMARY KEY (b_name, p_c, c_id)
);
To prevent repeated mapping error, you just have to specify which join should update the column like such:
#OneToMany(cascade = CascadeType.PERSIST)
#JoinTable(name = "bundle_pricing",
joinColumns = #JoinColumn(name = "bundle_name",
referencedColumnName = "name"))
#MapKeyJoinColumns({
#MapKeyJoinColumn(name = "bundle_name", insertable = false, updatable = false),
#MapKeyJoinColumn(name = "physical_currency"), #MapKeyJoinColumn(name = "coin_id")})
private Map<VirtualCurrency, Price> pricing = new LinkedHashMap<>();
NOTE the insertable = false, updatable = false for bundle_name in the MapKeyJoinColumn
remove the #MapKeyJoinColumn(name = "bundle_name") from MapKeyJoinColumns, because when we are creating the JoinColumn in JoinTable it will create the column we don't need to mention it again.
#JoinTable(
name = "bundle_pricing",
joinColumns = #JoinColumn(name = "bundle_name", referencedColumnName = "name"))
#MapKeyJoinColumns({
#MapKeyJoinColumn(name = "physical_currency"),
#MapKeyJoinColumn(name = "coin_id")
})

How to do One to One association in hibernate with foreign key and join table and unidirectional

I wish to have a one to one association with a join table in unidirectional way. -
Tables :
A (A_id, D_id, A_Data)
B (A_id, C_id) // Join table just contain relation between A and C
C (C_id, C_Data)
Class A {
.
.
#OneToOne(cascade = CascadeType.ALL)
#JoinTable(name = "B",
joinColumns = #JoinColumn(name = "A_id", referencedColumnName = "A_id"),
inverseJoinColumns = #JoinColumn(name = "C_id", referencedColumnName = "C_id"))
private C c;
}
I am using hibernate with jpa 2.0.
Entity D is not important in the model hence ignored.
I only wish to read data ,hence insert/update/delete use cases should not be concern, but one can suggest best practice in that case also.
This setup does not work. Can some one suggest how to do it in correct way?
It gives following exception
org.hibernate.MappingException: Unable to find column with logical name: A_id in org.hibernate.mapping.Table(A) and its related supertables and secondary tables
In order to get your desired schema:
// Given the following C entity
#Entity
public class C {
#Id
#Column(name = "C_ID")
private long id;
private String C_Data;
//...
}
// A Entity should be
#Entity
public class A {
#Id
#Column(name = "A_ID")
private long id;
private String A_Data;
#OneToOne(cascade = CascadeType.ALL )
#JoinTable(name = "B", joinColumns = #JoinColumn(name = "A_id"), inverseJoinColumns = #JoinColumn(name = "C_id", unique = true))
private C c;
//...
}
I've omitted referencedColumnName, so hibernate will map it to the entity primary key.
Note also that A_id column of B table will be the primary key.

"Repeated column in mapping for collection" for hibernate ManyToMany with same foreign key?

I have 4 tables as following:
create table market (
id int(6) unsigned auto_increment primary key,
market_id varchar(30) unique
);
create table market_channel_group (
id int(6) unsigned auto_increment primary key,
market_id varchar(30),
channel_group_id varchar(30),
unique index (market_id,channel_group_id)
);
create table market_channel (
id int(6) unsigned auto_increment primary key,
market_id varchar(30),
channel_id varchar(30),
unique index (market_id,channel_group_id)
);
create table market_channel_group_detail (
id int(6) unsigned auto_increment primary key,
market_id varchar(30),
channel_group_id varchar(30),
channel_id varchar(30),
unique index (market_id,channel_group_id, channel_id)
);
as you can see, market is OneToMany to market_channel_group, market_channel.
market_channel_group is ManyToMany to market_channel under specific market.
The problem is in my market_channel_group entity, I have following code:
#Entity(name = "market_channel_group")
#Table(name = "market_channel_group", uniqueConstraints = {#UniqueConstraint(columnNames = {"market_id", "channel_group_id"})})
public class MarketChannelGroup extends BaseEntity {
private static final long serialVersionUID = 1L;
public MarketChannelGroup() {
super();
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private int id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "market_id", referencedColumnName = "market_id")
private Market market;
#Column(name = "channel_group_id", length = 50)
private String channelGroupId;
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "market_channel_group_detail",
joinColumns = {#JoinColumn(name = "market_id", referencedColumnName = "market_id"), #JoinColumn(name = "channel_group_id", referencedColumnName = "channel_group_id")},
inverseJoinColumns = {#JoinColumn(name = "market_id", referencedColumnName = "market_id"), #JoinColumn(name = "channel_id", referencedColumnName = "channel_id")})
private List<MarketChannel> channels;
...
}
However, I got this exception:
Caused by: org.hibernate.MappingException: Repeated column in mapping for collection: MarketChannelGroup.channels column: market_id
at org.hibernate.mapping.Collection.checkColumnDuplication(Collection.java:343) ~[hibernate-core-4.3.6.Final.jar:4.3.6.Final]
...
How should I write the ManyToMany annotation correctly? or is there any problem of my design.
UPDATE
since we will import data from external resource, the auto increment id is not used as other tables' reference, each table has another index other than its own id.
For me, it was solved by adding insertable = false, updatable = false to the the #JoinColumn.

JPA : Delete object from unidirectional many-to-many relationship

I have a unidirectional relation between two entities and I want to remove property object from join table only. I tried this but it only removes the property object from template and not from database join table. How can I remove it from join table:
template.getProperties().remove(property);
Entity calss:
#Table(name = "template")
public class GridTemplate {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id_grid")
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "grid_property",
joinColumns =
#JoinColumn(name = "id_grid", referencedColumnName = "id"),
inverseJoinColumns =
#JoinColumn(name = "id_property", referencedColumnName = "id"))
private List<Property> properties;
}
join table:
CREATE TABLE [dbo].[grid_property](
[id_grid] [int] NOT NULL,
[id_property] [int] NOT NULL,
CONSTRAINT [PK_grid_property] PRIMARY KEY CLUSTERED
(
[id_grid] ASC,
[id_property] ASC)

How to specify FK names when using #JoinTable mapping?

I have the following mapping:
//...
#Table(name="A")
public class A{
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "A_B", joinColumns = {#JoinColumn(name = "A_ID")}, inverseJoinColumns = {#JoinColumn(name = "B_ID")})
public Set<B> getBs() {
return this.meals;
}
//...
}
//...
#Table(name="B")
public class B{
private int id;
private String description;
//...
}
How can specify the names of the foreign keys in table "A_B"? (FK_A_ID and FK_B_ID)
Thanks in advance,
Neuquino
You can use the #ForeignKey to specify the name of the foreign key constraint in the join table .
For example:
#ForeignKey(name="FK_A_ID" , inverseName="FK_B_ID")
#JoinTable(name = "A_B", joinColumns = {#JoinColumn(name = "A_ID")}, inverseJoinColumns = {#JoinColumn(name = "B_ID")})
public Set<B> getBs() {
return this.meals;
}
Then Table A_B has the following structure:
A column called A_ID which has the foreign key constraint to the primary key of Table A .The name of this foreign key is FK_A_ID
A column called B_ID which has the foreign key constraint to the primary key of Table B.The name of this foreign key is FK_B_ID

Categories

Resources