I have 2 entities O and D with a one to many relationship from O (one) to D (many). The relationship itself has an attribute - count.
What is the best way to model this using hibernate?
What I have currently is another entity OD representing the relationship. It has its own artificial key
The abbreviated version of the entities is as below
#Entity
class O {
#Id
private Long id;
#OneToMany(mappedBy = "o")
private Set<OD> ods;
}
#Entity
class OD {
#Id
private Long id;
#ManyToOne
private O o;
// This is uni-directional reln
#OneToOne
private D d;
private int count;
}
Is this the best way? I do not like the fact that the relationship has its own id, but is there a better way to model this relationship?
You can model the OD as #Embeddable, and change the owning side from #OneToMany to #ElementCollection e.g.
#Entity
public class O {
#Id
private Long id;
#ElementCollection
#CollectionTable( name = "OD")
private Set<OD> ods;
}
#Embeddable
public class OD {
// This is uni-directional reln
#OneToOne
private D d;
private int count;
}
The DDL statements would be almost the same with the distinction that the life-cycle of the OD would always be dependent on the life of its parent object, and would not hold an identity of its own
Related
I have the following entities:
#Entity
public class TableA {
#Id
#GeneratedValue(...)
private Long id;
private Timestamp updatedDateTime;
#Version
private int version;
}
#Entity
public class TableB{
#Id
#GeneratedValue(...)
private Long id;
#ManyToOne
#JoinColumn(name="fieldTableC")
private TableC paymentsData;
}
#Entity
public class TableC{
#Id
#Column(name = "fieldTableC")
private String fieldTableC;
private String someOtherField;
}
The problem I am facing, is that I cannot find any information on how to do the following scenario:
If either TableB or TableC gets updated, then I need hibernate to automatically increment the version in TableA. Should I add a FK of TableA to TableB & TableC ?
As you can see, I already have a #ManyToOne from TableB to TableC, if that helps in any way.
PS: I am using JpaRepository
I ended up by adding the child reference in parent, and parent reference into child. Whenever I want to save a child, I also update the parent updatedDateTime value. My method is #Transient, so everything will be saved in 1 transaction.
Also added CascadeType.SAVE_UPDATE, so that when saving parent, the child will also be saved
Eg:
Added to TableA:
#OneToMany(mappedBy = "tableA")
#Cascade(org.hibernate.annotations.CascadeType.SAVE_UPDATE)
private List<TableB> list= new ArrayList<>();
Added to TableB:
#ManyToOne
#JoinColumn(name = "tableA_root_id")
private TableA tableA;
I have two entities, which we'll call A and B. B always has A as a parent with a ManyToOne relation.
However, I need A to have a OneToOne relation with the latest record inserted in table B.
This is because I need to save multiple versions of B but 99% of the time will only need to use the most recent one.
This looks something like this:
#Data
#Entity
public class A {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Setter(AccessLevel.NONE)
private Long id;
/* Properties
...
*/
#OneToOne(optional = false)
private B latest;
}
#Data
#Entity
public class B {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Setter(AccessLevel.NONE)
private Long id;
/* Properties
...
*/
#Column(nullable = false)
private Date lastModified;
#ManyToOne(optional = false)
private A parent;
}
Now, the issue at hand is that I cannot seem to persist these entities as one always appears to be transient:
A cannot be persisted because latest references B, yet B is not persisted.
B cannot be persisted because parent references A, yet A is not persisted.
Attempting to do so results in:
java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation : B.parent -> A
I tried wrapping the code responsible for persisiting them in a #Transactional method but the same happens:
#Transactional
public void saveAB(A parent, B child) {
parent.setLatest(child);
child.setParent(parent);
Arepository.save(parent);
Brepository.save(child);
}
I also thought of disregarding the OneToOne relation from A to B, instead having latest as a transient #Formula field which would query B to take the most recent record. However, #Formula seems to be limited to primitives, not full entities.
What would be the proper way to do this with JPA? Am I approaching this the wrong way?
Since A and B depend on each other they should probably be considered a single aggregate with A being the aggregate root.
This means you'd have only an ARepository and also CascadeType.ALL on the relationships.
The solution was to apply #JoinFormula as explained here.
#Data
#Entity
public class A {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Setter(AccessLevel.NONE)
private Long id;
/* Properties
...
*/
#ManyToOne
#JoinFormula(value = "(SELECT b.id FROM b " +
"WHERE b.id = id ORDER BY b.lastModified DESC LIMIT 1)")
private B latest;
}
Then on B:
#ManyToOne(optional = false)
private A parent;
I have to join two tables and filter the result with a Where with Specifications and JPA. But I'm not very familiar with it.
The tables are for example:
public class A {
private Long id;
private Long secondId;
...
}
public class daughterA {
#JoinColumn (name = "id")
private Long idA;
...
}
and the WHERE is to be applied on secondId.
Thank you all for the help, I apologize for any inaccuracies, i'm beginning with these technologies.
First of all, your Join seems to be a one To Many join so you should make it as it is :
add the One annotation in the parent class being mapped by the name of the instance of it in the other class, this notation covers a Set or a List of objects of the daughters class
add the ManyToOne annotation in the daughter class, a daughter can only have one mother, and idA is not Long but it refers to the parent class it's in fact a foreign key
public class A{
#Id
private Long id;
private Long secondId;
#OneToMany(mappedBy="idA")
private Set<daughterA > daughters;
...
}
public class daughterA {
#ManyToOne
#JoinColumn (name = "id")
private A idA;
...
}
and for the where clause :
TypedQuery<Country> query =
em.createQuery("SELECT d FROM daughterA d WHERE d.idA.secondId = :secondId ", Country.class);
A results = query.setParameter("secondId",sencondId).getSingleResult();
I have entity called Shop and different types of shops (sport, clothes, tech...). That list of types will probably be predefined. One shop can have multiple types. What is the best way to represent that?
I created two entities Shop and Type.
#Entity
#Table(name = "store")
public class Store {
#GeneratedValue(strategy = GenerationType.AUTO)
#Id
private Long id;
...
}
#Entity
#Table(name = "type")
public class Type {
#GeneratedValue(strategy = GenerationType.AUTO)
#Id
private Long id;
private String name; //sport, clothes, tech...
}
What type of relationship between these two entities should I use?
Given that you said Type is probably predefined, it seems more reasonable to model it as enum, and making use of ElementCollection
(I have to admit that I haven't tried to use them both in combination, I believe it should work though :P )
public enum Type {
SPORT, CLOTHES, TECH
}
public class Shop {
#Id
private Long id;
#ElementCollection
#CollectionTable(
name="SHOP_TYPE",
joinColumns=#JoinColumn(name="SHOP_ID")
)
#Column(name="TYPE")
// mapping for enum by usertype or other way, depending on JPA version you are using
private List<Type> types;
}
Of course, you can model SHOP_TYPE as an entity (e.g. ShopType) if you want more complicated operations on it, but what described above looks to me a more reasonable domain model.
Even you do not want the Type to be predefined (i.e. you can create whatever type in your application), it is still more reasonable to model it as a ManyToMany relationship:
public class Type {
#Id
#Column(name="TYPE_ID")
private Long id
#Column(name="TYPE_NAME")
private String name;
}
public class Shop {
#Id
#Column(name="SHOP_ID")
private Long id;
#ManyToMany
#JoinTable(
name="SHOP_TYPE",
joinColumns=#JoinColumn(name="SHOP_ID"),
inverseJoinColumns=#JoinColumn(name="TYPE_ID"))
private List<Type> types;
}
Just one thing to note: It does not look right to have a Type entity which contains a String as type name, and refer to Shop (as some of the answer suggested). Type should be an entity of itself, and, for example, different shops having CLOTHES type should refer to same CLOTHES entity (unless you view types as some kind of arbitrary tag)
The Store and Type many to many relationship is linked with a third / join table named STORE_TYPE_MAPS.
Store Entity:
#Entity
#Table(name = "store")
public class Store {
#GeneratedValue(strategy = GenerationType.AUTO)
#Id
private Long id;
#ManyToMany(fetch = FetchType.LAZY, targetEntity=Type.class)
#JoinTable(name="STORE_TYPE_MAPS",
joinColumns=#JoinColumn(name="STORE_ID"),
inverseJoinColumns=#JoinColumn(name="TYPE_ID")
private Set<Type> types;
//... getter-setter
}
If Type is an Entity then make it ManyToMany
#ManyToMany
#JoinTable(name="Store_Type")
private List<Type> types;
also it can be an enum
I rather prefer to create a new entity called ShopType, the ManyToMany relationship will be created as explained below.
This new Entity allows you to have extra columns in the join table, "ShopType", (which can't be done with a simple #ManyToMany). For example, you can add this information: "the number of articles of each type in each shop".
The code is as follows:
public class Shop {
#Id
#Column(name="SHOP_ID")
private Long id;
#OneToMany(mappedBy = "shop", cascade = CascadeType.ALL)
private List<JoinAchatType> joinShopType = new ArrayList();
}
public class ShopType {
#ManyToOne
#JoinColumn(name = "SHOP_ID")
private Shop shop;
#ManyToOne
#JoinColumn(name = "TYPE_ID")
private Type type;
private int numberArticle;
}
public class Type {
#Id
#Column(name="TYPE_ID")
private Long id;
#OneToMany(mappedBy = "type", cascade = CascadeType.ALL)
private List<JoinAchatType> joinShopType = new ArrayList();
}
For more information check these links:
Mapping many-to-many association table with extra column(s)
.
The best way to use the #ManyToMany annotation with JPA and Hibernate.
i want to implement bi-directional One-To-Many relationship in my app engine application. I have two entities - entity A (parent) and entity B(child).
Parent :
#Entity
public class A implements Serializable {
#Id
private String aId;
#OneToMany(mappedBy = "objA", cascade = CascadeType.ALL)
List<B> bList;
getter().........setter()
}
Child :
#Entity
public class B implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Key bId;
#ManyToOne(fetch = FetchType.LAZY)
private A parentA;
getter().........setter()
}
Here,at first i persist object of class A and at that time i don't set its bList property. After that i create object of B and update setbList() of A which will automatically persist object of type B in datastore (as here i have set cascade=CascadeType.ALL).Now i want to access A from B objects.(parent from child) in my endpoint class which i am using in my android client. How can i achieve this?
You just need to add a reference to A in your B class
private A parentA;
parentA = //whatever you use when you update setbList()
Good luck!