I am trying to create a OneToMany
mapping with a LinkedHashMap
for my main entity Bundle
, that contains the entities VirtualCurrency
and Price
, but I am getting the following error:
Repeated column in mapping for collection: com.test.model.Bundle.pricing column: bundle_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:
bundle_name
physical_currency
and coin_id
e.g. the VirtualCurrency/VirtualCurrencyId
in order to get the amount
and discount_amount
e.g. Price
.
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 bundle
and bundle_pricing
tables, where the bundle_pricing
could just have all five fields (key and value) from the pricing
map).
Here is my main entity
@Setter
@Getter
@Entity
@Table(name = "bundle")
public class Bundle implements Serializable {
@Id
@Column(nullable = false)
private String name;
@OneToMany(cascade = CascadeType.PERSIST)
@JoinTable(
name = "bundle_pricing",
joinColumns = @JoinColumn(name = "bundle_name", referencedColumnName = "name"))
@MapKeyJoinColumns({
@MapKeyJoinColumn(name = "bundle_name"),
@MapKeyJoinColumn(name = "physical_currency"),
@MapKeyJoinColumn(name = "coin_id")
})
private Map<VirtualCurrency, Price> pricing = new LinkedHashMap<>();
...
}
The Key to the map
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "virtual_currency")
public class VirtualCurrency implements Serializable {
@EmbeddedId private VirtualCurrencyId virtualCurrencyId;
}
The key's PK/Composite Key
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Embeddable
public class VirtualCurrencyId implements Serializable {
@Column(name = "bundle_name")
private String bundleName;
@Column(name = "physical_currency")
private SomeEnum physicalCurrency;
@Column(name = "coin_id")
private String coinId;
}
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 bundle
(
name VARCHAR(100) NOT NULL PRIMARY KEY
...
);
CREATE TABLE virtual_currency
(
bundle_name VARCHAR(100) NOT NULL,
physical_currency TEXT NOT NULL,
coin_id VARCHAR(50) NOT NULL,
FOREIGN KEY (bundle_name) REFERENCES bundle (name) ON DELETE CASCADE,
PRIMARY KEY (bundle_name, physical_currency, coin_id)
);
CREATE TABLE price
(
id BIGSERIAL NOT NULL PRIMARY KEY,
amount NUMERIC,
discount_amount NUMERIC DEFAULT 0.00
);
CREATE TABLE bundle_pricing
(
bundle_name VARCHAR(100) NOT NULL,
physical_currency TEXT NOT NULL,
coin_id VARCHAR(50) NOT NULL,
price_id BIGSERIAL NOT NULL,
FOREIGN KEY (bundle_name, physical_currency, coin_id) REFERENCES virtual_currency (bundle_name, physical_currency, coin_id) ON DELETE CASCADE,
FOREIGN KEY (price_id) REFERENCES price (id) ON DELETE CASCADE,
PRIMARY KEY (bundle_name, physical_currency, coin_id)
);
CodePudding user response:
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
CodePudding user response:
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")
})