I am currently trying to extract a set of entities from a table with a composite key, but I only want to perform the join with id_a to get a set and not both(id_a and id_b) which would yield a single result.
This is not the original code, but it is an example of what I am trying to achieve.
#Entity
public class ItemA {
#EmbeddedId
private ItemId itemId;
#OneToMany
private Set<ItemB> itemsB = new HashSet<>();
}
#Embeddable
public class ItemID implements Serializable {
private Integer itemIDA;
private Integer itemIDB;
}
#Entity
public class ItemB {
#Id
private Integer itemIDA;
}
I have tried a couple of ways, mainly annotating the #OneToMany with #JoinColumn and also with #JoinTable
#OneToMany
#JoinTable(
name = "itemB",
joinColumns = { #JoinColumn(name = "itemIDA") },
inverseJoinColumns = { #JoinColumn(name = "itemIDA") }
)
private Set<ItemB> detalleUsuarios = new HashSet<>();
also I tried maybe trying to get inside of the ItemId class
#OneToMany
#JoinTable(
name = "itemB",
joinColumns = { #JoinColumn(name = "itemID.itemIDA") },
inverseJoinColumns = { #JoinColumn(name = "itemIDA") }
)
private Set<ItemB> detalleUsuarios = new HashSet<>();
But I get the following error
A Foreign key refering com.example.ItemA from com.example.ItemB has the wrong number of column. should be 2
Related
I have two entities connected with many-to-many relationship. For example:
#Entity
public class Account {
#Id
private Long id;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(
name = "account_games",
joinColumns = {#JoinColumn(name="account_id")},
inverseJoinColumns = {#JoinColumn(name="game_id")}
)
private Set<Game> games = new HashSet<>();
}
#Entity
public class Game {
#Id
private Long id;
#ManyToMany(mappedBy = "games", fetch = FetchType.LAZY)
List<Account> accounts = new ArrayList<>();
}
So, there is a table account_games(account_id, game_id) in mysql describing entities many-to-many relations.
I don't want to have Game entity anymore. Is there a way to get rid of Game and leave gameId relation only? So, I'd like to have code something like that:
#Entity
public class Account {
#Id
private Long id;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(
name = "account_games",
joinColumns = {#JoinColumn(name="account_id")},
inverseJoinColumns = {#JoinColumn(name="game_id")}
)
private Set<Long> gameIds = new HashSet<>();
}
without making changes in database.
I've tried different configuration on javax.persistance annotations, but none worked
You can use #ElementCollection and #CollectionTable to achieve that.
#Entity
public class Account {
#Id
private Long id;
#ElementCollection(fetch = FetchType.LAZY)
#CollectionTable(name = "account_games", joinColumns = #JoinColumn(name = "account_id"))
#Column(name = "game_id", nullable = false)
private Set<Long> gameIds = new HashSet<>();
}
You may have to change the query on how to filter data using gameId. Element Collection Query
I want to join only one column from another table.
I have 2 entities now:
#Entity
public class Message {
....
#ManyToOne
#JoinColumn(name = "ATTRIBUTE_ID")
private Attribute attribute;
}
#Entity
#Table(name = "ATTRIBUTE_TABLE")
public class Attribute {
#Id
#Column(name = "ID")
private Long id;
#Column(name = "NAME")
private String name;
}
And I want to simplify code and don't use entity for only one column:
#Entity
#SecondaryTable(name = "ATTRIBUTE_TABLE", pkJoinColumns =
#PrimaryKeyJoinColumn(name = "ID", referencedColumnName = "ATTRIBUTE_ID")),
public class Message {
....
#Column(table = "ATTRIBUTE_TABLE", name = "NAME")
private String attribute;
}
But #SecondaryTable JoinColumn cannot reference a non-primary key.
How to add a column from another table without using additional entity for it?
I have these BaseNews and News entity:
#MappedSuperclass
public class BaseNews extends Model {
public static Model.Finder<Long, News> find = new Model.Finder<Long, News>(News.class);
public static News getNewsById(Long newsId) {
return find.byId(newsId);
}
public static List<News> getNewsList(int pageIndex, int pageSize) {
return find.where()
.findPagedList(pageIndex, pageSize)
.getList();
}
}
#Entity
#Table(name = "news")
public class News extends BaseNews implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// #ManyToOne
// private News baseNews;
#OneToMany(cascade = CascadeType.ALL)//,mappedBy = "baseNews")
#JoinTable(name = "news_similar",
joinColumns = {#JoinColumn(name = "base_news_id")},
inverseJoinColumns = {#JoinColumn(name = "similar_news_id")}
)
private List<News> similarNews;
//getters, setters...
}
In both uni and bidirectional case
select t0.id c0, t0.base_news_id c1 from news t0
gives error Unknown column base_news_id
Am I doing it wrong way?
Should I create new Entity NewsSimilar instead of using jointable?
Actually I am reversing existing table.
create table news_similar
(
id int auto_increment primary key,
base_news_id int not null,
similar_news_id int not null,
constraint news_similar_ibfk_1 foreign key (base_news_id) references news (id) on update cascade on delete cascade,
constraint news_similar_ibfk_2 foreign key (similar_news_id) references news (id) on update cascade on delete cascade
)
Edit: news_id was completely unrelated problem from other field, anyway solved it.
It turns out that I have ManyToMany relation so, the solution is like this
#Entity
#Table(name = "news")
public class News extends BaseNews implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "news_similar",
joinColumns = {#JoinColumn(name = "base_news_id")},
inverseJoinColumns = {#JoinColumn(name = "similar_news_id")}
)
private List<News> similarNews;
//getters, setters...
}
Came by this solution while reading this article:
https://www.thoughts-on-java.org/ultimate-guide-association-mappings-jpa-hibernate/
Recently I created a project and in my models I have ManyToMany back references.
My model is like below:
#Entity
public class A {
#ManyToMany(mappedBy = "parents", fetch = FetchType.EAGER)
private Set<A> children = new HashSet<>();
#ManyToMany
#JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
#JoinTable(
name = "link_a_recursion",
joinColumns = #JoinColumn(name = "child_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "parent_id", referencedColumnName = "id")
)
private Set<A> parents = new HashSet<>();
//I removed the rest ( setter, getter and other fields )
}
When I fetch this model and I want to load children it throws StackOverFlowException error ( Recursive exception )
I want to know is there any way to say to hibernate just load one level of associate and don't go deep.
For clarify:
A.children[0].children[0].children should be null to stop recursion
I want to load the first children not all the children inside of the other children
Edited:
I add another entity:
#Entity
public class B {
#OneToMany(mappedBy = "b")
private Set<A> entities = new HashSet<>();
//setter, getter
}
and add below to A entity:
#ManyToOne
private B b;
then I changed below:
#ManyToMany(mappedBy = "parents", fetch = FetchType.EAGER)
to
#ManyToMany(mappedBy = "parents", fetch = FetchType.LAZY)
and in my BService my findOne function is like below:
#Transactional(readOnly = true)
public B findOne(Long id) {
B b = repository.findOne(id);
for (A a: b.getEntities()) {
a.getChildren().size();
}
return b;
}
but again I'm getting error :(
Try lazy fetch instead
#ManyToMany(mappedBy = "parents", fetch = FetchType.LAZY)
I'm implementing a #ManyToOne bidirectional relationship with a join table using hibernate, but when I'm persisting some data, the hibernate claims that the record in relationship table is being inserted twice, violating the unique constraint, as the error message below shows:
ERROR: org.hibernate.engine.jdbc.spi.SqlExceptionHelper - ERROR: duplicate key value violates unique constraint "tillage_sample_pkey"
Detail: Key (id_tillage, id_sample)=(82, 110) already exists.
I have the following tables:
Tillage (id, some other data) (One Tillage can have many samples)
Sample (id, some other data) (One Sample can have one Tillage only)
tillage_sample (id_tillage, id_sample) PK (id_tillage, id_sample)
When I create a Tillage object, I fill with a Sample. In the Sample Object, I point with the Tillage object, creating a "double binding".
I guess that this "double bind" is causing the trouble, as Tillage/Sample relationship is persisted by hibernate when is saving the Tillage and repeating the step when it tries to persist the Tillage inside the Sample (which is the same tillage object).
Here Goes my code, to help you to understand my issue:
Tillage.java
#Entity
#Table(name = "tillage")
public class Tillage implements Serializable {
private static final long serialVersionUID = 3605331584324240290L;
#Id
#GeneratedValue(generator = "tillage_id_seq", strategy = GenerationType.SEQUENCE)
#SequenceGenerator(name = "tillage_id_seq", sequenceName = "tillage_id_seq", allocationSize = 1)
private Integer id;
#Column(name = "name")
private String name;
// Other simple attributes
#ManyToOne
#JoinColumn(name = "id_farm")
#JsonBackReference
private Farm farm;
// This relation is the problematic one
#OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name = "tillage_sample",
joinColumns = { #JoinColumn(name = "id_tillage") },
inverseJoinColumns = {#JoinColumn(name = "id_sample") })
private List<Sample> sampleList;
// Although similar, this one is doing OK
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "tillage_owner",
joinColumns = { #JoinColumn(name = "id_tillage") },
inverseJoinColumns = {#JoinColumn(name = "id_owner") })
private List<Owner> ownerList;
// getters & setters
}
Sample.java
#Entity
#Table(name = "sample")
public class Sample implements Serializable {
private static final long serialVersionUID = 7064809078222302493L;
#Id
#GeneratedValue(generator = "sample_id_seq", strategy = GenerationType.SEQUENCE)
#SequenceGenerator(name = "sample_id_seq", sequenceName = "sample_id_seq", allocationSize = 1)
private Integer id;
#Column(name = "name")
private String name;
// Other simple attributes
// This completes the relation Tillage-Sample
#ManyToOne(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name = "tillage_sample",
joinColumns = { #JoinColumn(name = "id_sample") },
inverseJoinColumns = {#JoinColumn(name = "id_tillage") })
private Tillage tillage = new Tillage();
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
#JoinTable(name = "sample_sample_item",
joinColumns = { #JoinColumn(name = "id_sample") },
inverseJoinColumns = {#JoinColumn(name = "id_sample_item") })
private List<SampleItem> sampleItemList;
// Getters and Setters
}
SomeService.java
...
#Override
public Tillage toTillage(TillageDTO dto) {
Tillage tillage = new Tillage();
tillage.setName(dto.getNameTillage());
// Fill the samples of the tillage
for(ArrSample sample : dto.getSamples().getArrSample()){
Sample s = new Sample();
s.setName(sample.getName());
// Setting the tillage in the Sample object
s.setTillage(tillage);
// Fill the items of the sample
for(Array arr : sample.getAreas().getArray()){
SampleItem si = new SampleItem();
si.setProduction(Double.parseDouble(arr.getProduction()));
// Double binding between sample and sampleItem
si.setSample(s);
s.getSampleItemList().add(si);
}
// Adding a sample to Tillage
tillage.getSampleList().add(s);
}
return tillage;
}
public void save(TillageDTO dto){
Tillage t = this.toTillage(dto);
// The error occurs when we persist the data
// The entityManager is Autowired by Spring and works in other places
entityManager.persist(tillage);
}
That's not a bidirectional OneToMany. That's too separate unidirectional associations using the same join table.
In a bidirectional association, one side must be the inverse of the other side. For a OneToMany, the One side must be the inverse side:
#OneToMany(mappedBy = "tillage", cascade=CascadeType.ALL, fetch = FetchType.EAGER)
private List<Sample> sampleList;