Lets say I have bidirectional one-to-many association between Parent-Child, mapped as follows:
public class TradingAccount {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(mappedBy = "tradingAccount", cascade = CascadeType.ALL, orphanRemoval = true)
private List<UnderlyingPerTradingAccount> underlyingPerTradingAccounts;
#Version
private Long version;
}
and
public class UnderlyingPerTradingAccount {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
private TradingAccount tradingAccount;
private Boolean enableBuy;
private Boolean enableSell;
}
now when i update a TradingAccount this exeception I get exception:
object references an unsaved transient instance - save the transient instance before flushing
Related
We have a problem with fetching by Id of a subselected entity
Here the structure
public class A {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
//Other class members;
}
public class B {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ValueRestriction("NOTNULL")
#ManyToOne
#JoinColumn(name = "C_ID")
private C c;
#ValueRestriction("NOTNULL")
#JsonIgnore
#ManyToOne
#JoinColumn(name = "A_ID")
private A a;
//Other class members;
}
public class C {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#JsonIgnore
#OneToMany(mappedBy = "c")
#Fetch (FetchMode.SELECT)
private List<B> bs;
#ValueRestriction("NOTNULL")
#JsonIgnore
#ManyToOne
#JoinColumn(name = "A_ID")
private A a;
//Other class members;
}
So when we fetch over hibernate
em().find(B.class, id);
the Hibernate query also fetches the columns of A in the C entity.
This lead in a bigger Entitystructure to an
target lists can have at most 1664 entries
(This is a simple demonstration)
In our case we need the references of Entity A in all of these sub Entities
How can we prevent hibernate to fetch the same object multiple times if it is the ame.
In our cases A will always be the SAME in Entity B and Entity C. The Case that Entity B has a different A Entity than in the C Entity is in our structure not possible.
The problem is that #ManyToOne and #OneToOne by default do eager fetching. Switch to lazy fetching #ManyToOne(fetch = LAZY) to avoid this.
I work with an embedded H2 database in which I use the #OneToMany relationship to relate an entity instance (product) to multiple instances of the other entities (suppliers); it's useful when I have specific suppliers for a particular product.
However now, I want to associate all the suppliers with every single product; I don't want to generate in my supplier table different supplier records for each product, instead I want to have only 5 records (5 suppliers) in my supplier table which are associated to every single product, it few words I want to achieve something like "one to all", is it possible to do it using JPA annotations?
Product entity
#Entity
public class Product {
#Id
private String productCode;
#OneToMany
#JoinColumn(name = "supplier_id", referencedColumnName = "productCode")
private List<Supplier> suppliers;
}
Supplier entity
#Entity
public class Supplier {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
private String name;
}
Unidirectional #OneToMany association:
#Entity
public class Product {
#Id
// #Column(name = "id") maybe
// #GeneratedValue maybe
private String productCode;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) // according to your need
private List<Supplier> suppliers;
...
}
And,
#Entity
public class Supplier {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
...
}
#ManyToOne association:
#Entity
public class Product {
#Id
// #Column(name = "id") maybe
// #GeneratedValue maybe
private String productCode;
...
}
And,
#Entity
public class Supplier {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne
#JoinColumn(name = "product_id", foreignKey = #ForeignKey(name = "PRODUCT_ID_FK"))
private Product product;
private String name;
...
}
Lets say I have bidirectional one-to-many association between Parent-Child, mapped as follows:
TradingAccount.java
public class TradingAccount {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(mappedBy = "tradingAccount", cascade = CascadeType.ALL, orphanRemoval = true)
private List<UnderlyingPerTradingAccount> underlyingPerTradingAccounts;
#Version
private Long version;
}
UnderlyingPerTradingAccount.java
public class UnderlyingPerTradingAccount {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(cascade = {CascadeType.PERSIST})
private TradingAccount tradingAccount;
private Boolean enableBuy;
private Boolean enableSell;
}
this code work, but the problem after saving or updating Trading Account I found new three trading account in the database (primary key + null in all other columns)
Suppose, we have two entities, first one:
#Entity
#Table(name = "entitya")
public class EntityA {
#Id
#Column(name = "id")
private Long id;
#Column(name = "name")
private Long name;
#OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
private Set<EntityB> childEntities;
}
and the second:
#Entity
#Table(name = "entityb")
public class EntityB {
#Id
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#Column(name = "master")
private Boolean master;
#ManyToOne
#JoinColumn(name = "parent")
private EntityA parent;
}
So far, so good. However underlying database tables and constrains enforce that for any entityA there can be only one EntityB with boolean field master set to true. I can extract it by adding following method to entityA:
public entityB getMasterChild() {
for(entityB ent : childEntities) {
if(ent.isMaster()) {
return ent;
}
}
}
The question is, can I create #OneToOne relationship in EntityA that can express that rule, so that entityA can have additional masterChild member of type entityB?
If I understood you correctly you want to create/define a relationship between two entities based on a value of some entity's property. The think is that relationship between entities is defined on entities count (how many entities can has the other entity) and not on some entity's property value.
However
If you really want to use #OneToOne mapping for masterChild I would recommend creating a separate table/entity for it. Once this is done, you can include this new MasterChild entity into EntityA and annotate it with #OneToOne.
Here is new MasterChild entity
#Entity
public class MasterChild extends EntityB{
#Id
#Column(name = "id")
private Long id;
}
Note that I have removed 'master' from EntityB as it is no longer needed
#Entity
#Table(name = "entityb")
public class EntityB {
#Id
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#ManyToOne
#JoinColumn(name = "parent")
private EntityA parent;
}
And here is modified EntityA
#Entity
#Table(name = "entitya")
public class EntityA {
#Id
#Column(name = "id")
private Long id;
#Column(name = "name")
private Long name;
#OneToOne
private MasterChild master;
#OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
private Set<EntityB> childEntities;
}
I'm trying to get rid of the following error:
The attribute [lcritical] in entity
class [class
pl.pwc.docs.pl704.PL704_Error] has a
mappedBy value of [pl704_error] which
does not exist in its owning entity
class [class
pl.pwc.docs.pl704.PL704_Error_Critical].
If the owning entity class is a
#MappedSuperclass, this is invalid,
and your attribute should reference
the correct subclass.
PL704 #Entity class:
#Entity
public class PL704 implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private int Status;
private String Comments;
#OneToMany(mappedBy="pl704", cascade=CascadeType.ALL, targetEntity=PL704_Error.class, fetch=FetchType.EAGER)
private Collection lerror = new ArrayList<PL704_Error>();
//getters, setters...
PL704_Error #Entity class:
#Entity
public class PL704_Error implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String ErrorType;
private String ErrorReason;
private String ErrorLocation;
private String OriginalAttributeValue;
#ManyToOne
#JoinColumn(name = "PL704_ID", referencedColumnName = "ID")
private PL704 pl704;
#OneToMany(mappedBy="pl704_error", cascade=CascadeType.ALL, targetEntity=PL704_Error_Critical.class, fetch=FetchType.EAGER)
private Collection lcritical = new ArrayList<PL704_Error_Critical>();
//getters, setters...
PL704_Error_Critical #Entity class:
#Entity
public class PL704_Error_Critical implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "PL704_ERROR_ID", referencedColumnName = "ID")
private PL704_Error error;
//getters, setters...
Summing up, One PL704 can have many PL704_Error. One PL704_Error can have many PL704_Error_Critical.
How should I change my code to fix an error?
Used: EclipseLink 2.1.1, H2 Embedded.
It should be
#OneToMany(mappedBy="error", cascade=CascadeType.ALL,
targetEntity=PL704_Error_Critical.class, fetch=FetchType.EAGER)
private Collection lcritical = new ArrayList<PL704_Error_Critical>();
look at the corresponding property name in PL704_Error_Critical:
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "PL704_ERROR_ID", referencedColumnName = "ID")
private PL704_Error error;
The mapped by attribute spelling is not correct, maybe this is the cause:
In class PL704_Error the lcritical attribute is reversed mappedBy Attribute
#OneToMany(mappedBy="pl704_error"...
But the variable in PL704_Error_Critical is called only error.