An entity X has a list of entity Y and the entity Y has an instance of entity Z.
The relation between X to Y is OneToMany and the relation between Y to Z is ManyToOne.
I want to retrieve X and have all the associated entities retrieved with them as well.
What HQL query do I write so that I get the whole chain retrieved all at once. At present its hibernateTemplate.find("from X").
or What annonations do I use for it?
X=ServiceProvider, Y=BusinessLocations.java, Z=State.java
I have the entities annotated below and I am having the whole chain persisted into database but when i try to retrieve the list of Y(BusinessLocation), I get
nothing.
What do I do join X with Y and Y with Z?
Below are the entities x, Y and Z.
ServiceProvider.java
#Entity
public class ServiceProvider implements Serializable{
private Long id;
private Set<BusinessLocation> businessLocations = new HashSet<BusinessLocation>();
#Id
#GeneratedValue
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#OneToMany(mappedBy="serviceProvider", targetEntity=BusinessLocation.class, cascade=CascadeType.ALL, fetch=FetchType.EAGER)
public Set<BusinessLocation> getBusinessLocations() {
return businessLocations;
}
public void setBusinessLocations(Set<BusinessLocation> businessLocations) {
this.businessLocations = businessLocations;
}
public boolean equals(Object obj) {
if(!(obj instanceof ServiceProvider)) return false;
ServiceProvider other = (ServiceProvider) obj;
return new EqualsBuilder().append(businessLocations, other.businessLocations).isEquals();
}
}
BusinessLocation.java
#Entity
public class BusinessLocation implements Serializable{
private Long id;
private String address;
private String city;
private State state;
private String pincode;
private ServiceProvider serviceProvider;
public BusinessLocation() {
}
#Id
#GeneratedValue
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name="state_id")
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public void setPincode(String pincode) {
this.pincode = pincode;
}
public String getPincode() {
return pincode;
}
#ManyToOne
#JoinColumn(name="serviceProvider_id")
public ServiceProvider getServiceProvider() {
return serviceProvider;
}
public void setServiceProvider(ServiceProvider serviceProvider) {
this.serviceProvider = serviceProvider;
}
public boolean equals(Object obj) {
if( !(obj instanceof BusinessLocation)) return false;
BusinessLocation other = (BusinessLocation) obj;
return new EqualsBuilder().append(address, other.address).append(city, other.city).append(state, other.state).append(pincode,
other.pincode).append(serviceProvider, other.serviceProvider).isEquals();
}
public int hashCode() {
return new HashCodeBuilder().append(address).append(city).append(state).append(pincode).append(serviceProvider).toHashCode();
}
}
State.java
#Entity
public class State implements Serializable {
private Long id;
private String abbreviatedName;
private String name;
private List<BusinessLocation> businessLocations;
#Id
#GeneratedValue
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getAbbreviatedName() {
return abbreviatedName;
}
public void setAbbreviatedName(String abbreviatedName) {
this.abbreviatedName = abbreviatedName;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
#OneToMany(mappedBy="state", targetEntity=BusinessLocation.class, cascade=CascadeType.ALL, fetch=FetchType.EAGER)
public List<BusinessLocation> getBusinessLocations() {
return businessLocations;
}
public void setBusinessLocations(List<BusinessLocation> businessLocations) {
this.businessLocations = businessLocations;
}
public boolean equals(Object obj) {
if(! (obj instanceof State)) return false;
State other = (State) obj;
return new EqualsBuilder().append(abbreviatedName, other.abbreviatedName).append(name, other.name).append(businessLocations,
other.businessLocations).isEquals();
}
public int hashCode() {
return new HashCodeBuilder().append(name).append(abbreviatedName).append(businessLocations).toHashCode();
}
}
Could someone help me out here?
Thanks
What about:
Query q - entityManager.createQuery("Select x from ServiceProvider x inner join x.businessLocations as y and inner join y.state as z where x.id = ?1");
I have the entities annotated below and I am having the whole chain persisted into database but when i try to retrieve the list of Y (BusinessLocation), I get... nothing
You should activate SQL logging to see what is happening and check the data because the annotation part looks correct:
the one-to-many between ServiceProvider and BusinessLocation is EAGER
the many-to-one between BusinessLocation and State is EAGER (by default)
So the whole chain should be retrieved eagerly. If this is not what is happening, you might want to check the data and the SQL, hence the suggestion.
As an alternative to EAGER associations, you could use a FETCH JOIN to prefetch the related data:
FROM ServiceProvider provider
INNER JOIN FETCH provider.businessLocations location
LEFT JOIN FETCH location.state
But note that JPA 1.0 does not allow nested join fetches in JPQL, this is Hibernate specific.
References
Hibernate Core Reference Guide
14.3. Associations and joins
JPA 1.0 specification
Section 9.1.22 "ManyToOne Annotation"
Section 4.4.5.3 "Fetch Joins"
Related
Is it possible in plain JPA or Hibernate a composite key, where an element of the composite key is a sequence and the other element is a mapped with a foreign key.
I have a composite key in my table and part of it needs to be generated by a sequence.
I tried the following, but it doesn't work
class produit
#Entity
public class Produit{
#EmbeddedId
private ProduitClientPK id=new ProduitClientPK();
private Client client;
public ProduitClientPK getId() {
return id;
}
public void setId(ProduitClientPK id) {
this.id = id;
}
#JsonIgnore
#ManyToOne
#JoinColumn(name="FK_CLIENT")
public Client getClient() {
return client;
}
public void setClient(Client client) {
this.client = client;
}
}
class composite key :
#Embeddable
public class ProduitClientPK implements Serializable {
private long fkproduit;
private long clientSeq;
#Column(name = "FK_PRODUIT")
#Id
public long getFkProduit() {
return fkproduit;
}
public void setFkProduit(long fkproduit) {
this.fkproduit= fkproduit;
}
#Column(name = "CLIENT_SEQ")
#Id
public long getclientSeq() {
return clientSeq;
}
public void setClientSeq(long clientSeq) {
this.clientSeq= clientSeq;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PolPolAvnEntityPK that = (PolPolAvnEntityPK) o;
return fkPolice == that.fkPolice &&
avnSeq == that.avnSeq;
}
#Override
public int hashCode() {
return Objects.hash(fkPolice, avnSeq);
}
}
class client :
#Entity
public class Client {
private Long id;
private Set<Produit> produits;
#Id
#Column(name = "ID_PRODUIT")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#OneToMany(mappedBy = "client", cascade = CascadeType.ALL, orphanRemoval = true)
public Set<Produit> getProduits() {
return produits;
}
public void setProduits(Set<Produit> avenants) {
this.produits = produits;
}
public void addProduits(Produit produit){
produit.setClient(this);
produits.add(produit);
}
}
Your model does not make much sense, unless I misunderstood it. Why do you need FK_PRODUIT to be part of the primary key? If you are using a sequence for CLIENT_SEQ, this is enough to make the row unique. Apart from that, shouldn't this CLIENT_SEQ value be generated when persisting a Client? IMO you should be using something like the following:
#Entity
public class Produit{
#Id
#GeneratedValue
private Long id;
private Client client;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#JsonIgnore
#ManyToOne
#JoinColumn(name="FK_CLIENT")
public Client getClient() {
return client;
}
public void setClient(Client client) {
this.client = client;
}
}
I've met with the same issue not so long time ago. It would be better not to use #EmbeddedId in your case if you want one of PK fields to be generated by your database. I'm not expert in Hibernate, but as I know Hibernate doesn't try to set values to ID fields only if they are annotated by #GeneratedValue. Only this annotation can tell Hibernate to rely on database sequences. And you cannot do it in Embeddable class.
Try just use one #Id field if you want one to be generated.
In my project I try yo use Spring data Jpa. My find methods(findById, findAll) works correctly, but delete and save method works with problems. Delete method delete only from duck table. Save doesn't work:
Exception in thread "main" org.springframework.orm.jpa.JpaObjectRetrievalFailureException: Unable to find springdata.entities.FrogJpa with id 2; nested exception is javax.persistence.EntityNotFoundException: Unable to find springdata.entities.FrogJpa with id 2
I have 2 entities: Frog and Duck. Every ducks have 1 Frog(OneToOne). There are problems with entities relationship?
There are my entities class:
#Entity
#Table(name = "DUCKS")
public class DuckJpa implements Serializable {
#Id
private int id;
#Column(name = "NAME")
private String name;
#Column(name = "FLY")
private String flyBehavior;
#Column(name = "QUACK")
private String quackBehavior;
#OneToOne(optional = false)
#JoinColumn(name = "FROG_ID", unique = true, nullable = false, updatable = false)
private FrogJpa frogJpa;
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setFlyBehavior(String flyBehavior) {
this.flyBehavior = flyBehavior;
}
public void setQuackBehavior(String quackBehavior) {
this.quackBehavior = quackBehavior;
}
public void setFrogJpa(FrogJpa frogJpa) {
this.frogJpa = frogJpa;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public String getFlyBehavior() {
return flyBehavior;
}
public String getQuackBehavior() {
return quackBehavior;
}
public FrogJpa getFrogJpa() {
return frogJpa;
}
And Frog:
#Entity
#Table(name = "FROGS")
public class FrogJpa {
#OneToOne(optional = false, mappedBy = "frogJpa")
private DuckJpa duckJpa;
#Id
private int id;
#Column(name = "name")
private String name;
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setDuckJpa(DuckJpa duckJpa) {
this.duckJpa = duckJpa;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public DuckJpa getDuckJpa() {
return duckJpa;
}
}
My service class:
public interface DuckService {
List<DuckJpa> findAll();
Optional<DuckJpa> findById(Integer i);
DuckJpa save(DuckJpa duckJpa);
void delete(DuckJpa duckJpa);
}
And it's implementation:
#Service("springJpaDuckService")
#Transactional
public class DuckServiceImpl implements DuckService {
#Autowired
private DuckJpaRepository duckJpaRepository;
#Transactional(readOnly = true)
public List<DuckJpa> findAll() {
return new ArrayList<>(duckJpaRepository.findAll());
}
#Override
public Optional<DuckJpa> findById(Integer i) {
return duckJpaRepository.findById(i);
}
#Override
public DuckJpa save(DuckJpa duckJpa) {
duckJpaRepository.save(duckJpa);
return duckJpa;
}
#Override
public void delete(DuckJpa duckJpa) {
duckJpaRepository.delete(duckJpa);
}
Use #OneToOne(cascade=CascadeType.ALL, fetch = FetchType.LAZY).
For more information please refer What is cascading in Hibernate?
I'm using JPA and have some difficulties to understand how the One-To-Many Realtionship works.
I have the following two classes:
#Entity
public class myCheck {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
protected int Check_id;
#Column
private String name;
#ManyToOne
private mySystem system;
#Override
public String toString() {
return this.name;
}
public int getId() {
return Check_id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public mySystem getLinkSystem() {
return system;
}
public void linkSystem(mySystem system) {
this.system = system;
}
}
and:
#Entity
public class mySystem {
#Id
#GeneratedValue
#Column(name = "system_id")
protected int system_id;
#Column
public String name;
#ManyToOne(cascade=CascadeType.ALL)
private mySystem parent;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "system", fetch = FetchType.EAGER)
private List<myCheck> checks;
public mySystem() {
//subSystems = new ArrayList<mySystem>();
checks = new ArrayList<myCheck>();
}
public boolean linkCheck(myCheck hc) {
return checks.add(hc);
}
public boolean unlinkCheck(myCheck hc) {
return checks.remove(hc);
}
public List<myCheck> getlinkedChecks() {
return checks;
}
public myCheck getLinkCheck(int hcId) {
for (myCheck hc : checks) {
if (hc.getId() == hcId)
return hc;
}
return null;
}
public int getId() {
return system_id;
}
public void setId(int id) {
this.system_id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return this.getName();
}
}
Now I have an existing System in my database, which is loaded:
// load System
EntityManager entityManager1 = entityManagerFactory.createEntityManager();
List<mySystem> systems = entityManager1.createQuery("from mySystem").getResultList();
entityManager1.close();
I want to add two new checks to Systems. What is working is:
EntityManager entityManager2 = entityManagerFactory.createEntityManager();
entityManager2.getTransaction().begin();
myCheck check = new myCheck();
check.setName("Check 1");
check.linkSystem(systems.get(0));
entityManager2.persist(check);
myCheck check2 = new myCheck();
check2.setName("Check 2");
check2.linkSystem(systems.get(0));
entityManager2.persist(check2);
entityManager2.merge(systems.get(0));
entityManager2.getTransaction().commit();
entityManager2.close();
But I can't do this:
EntityManager entityManager2 = entityManagerFactory.createEntityManager();
entityManager2.getTransaction().begin();
myCheck check = new myCheck();
check.setName("Check 1");
systems.get(0).linkCheck(check);
entityManager2.persist(check);
myCheck check2 = new myCheck();
check2.setName("Check 2");
systems.get(0).linkCheck(check);
entityManager2.persist(check2);
entityManager2.merge(systems.get(0));
entityManager2.getTransaction().commit();
entityManager2.close();
The second solution will save the checks, but I don't link them with the system.
Has someone a explanation for this? I really want to understand this.
You have bidirectional relation which means each side of the relation should have a reference to the other side.
so in your persistence logic you will also need to inject the system in your check
myCheck check = new myCheck();
check.setName("Check 1");
check.linkSystem(systems.get(0);
systems.get(0).linkCheck(check);
entityManager2.persist(check);
But in this case you will have a problem if your (systems.get(0)) is not attached to the persistence context because you will be having reference to deatached object when persisting the check, you can either put Cascade on the system inside check class or instead persist the system, it already cascades the check so the check will be persisted
My goal :
In Spring MVC I have to save mobile phone contact list into database.
example:
phone1 sonia 2554654 work
2554654 home
multiple phone_number with multiple phone_Number type
contacts table
id,
contact_name
phone_number
phone_type
in my java class I have
public class ContactMobile {
private String type;
private String number;
public ContactMobile() {
}
public ContactMobile(String type, String number) {
super();
this.type = type;
this.number = number;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
and here I use SET for phone number and type
#Entity
#Table(name = "_contact")
public class MobileContact {
private String id;
private String fullname;
private Set<ContactMobile> mobileNumbers;
public MobileContact(String fullname, Set<ContactMobile> mobileNumbers) {
super();
this.fullname = fullname;
this.mobileNumbers = mobileNumbers;
}
#Id
#Column(name = "Id")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Column(name = "fullname")
public String getFullname() {
return fullname;
}
public void setFullname(String fullname) {
this.fullname = fullname;
}
public Set<ContactMobile> getMobileNumbers() {
return mobileNumbers;
}
public void setMobileNumbers(Set<ContactMobile> mobileNumbers) {
this.mobileNumbers = mobileNumbers;
}
public MobileContact() {
super();
}
}
I am using hibernate to store data..
my question is in my MobileContact class in
public Set<ContactMobile> getMobileNumbers() {
return mobileNumbers;
}
what annotation I have to use here to save multiple phonenumbers?
The MobileContact entity has many ContactMobile, it is a OneToMany relation. In your ContactMobile table, you should has a field for the id of MobileContact, like mobile_contact_id, and set the join column on that field as below in your ContactMobile:
#OneToMany(fetch = FetchType.LEZY)
#JoinColumn(name = "mobile_contact_id")
private Set<ContactMobile> mobileNumbers;
You can get the detail about the relation in this.
You can use the Embeddables (instead of Entities) for very simple value objects like MobileContact (then they do not need an ID, and the are no just simple value objects without own identity)
#Embeddable
public class ContactMobile {...
//implement an equals and hashcode method!
}
public class MobileContact {
...
#ElementCollection
private Set<ContactMobile> mobileNumbers;
...
}
#See Java Persistence/ElementCollection
I would like to build a simple ORM/database permission system where I have users, groups and rights:
Each user can be a member of multiple groups, every group can have multiple users as members.
Each relationship between user and group has an additional piece of information: rights.
The idea is that each user can have different rights in each group.
How should my entities look like so I can query things
from the "group view" like "retrieve all members of this group"
and the "user view" like "retrieve all groups this user is a member in"
as well as "given this user and this group, which rights does the user have"?
I'm using Java 6 with JPA2 annotations and EclipseLink.
I think you might want to look at implementations already provided by the application server community. Typically speaking, what you've described is a definition of form based authentication.
http://tomcat.apache.org/tomcat-5.5-doc/config/realm.html
Basically speaking, the relationship is:
User
+ Role[]
Once configured this allows frameworks such as JSF (but you'll notice I'm accessing the Tomcat session here) to query for a specific role. The code below is taken from a basic form-based authentication scheme I have on a small web-app, and it is in dire need of refactoring, I've just had higher priorities
public boolean isUserInRole(Roles role)
{
return FacesContext.getCurrentInstance().getExternalContext().isUserInRole(role.getRoleValue());
}
In this case Roles is a (poorly named) enum type that is stored in my "Role" Entity:
#Entity
#Table(name = "role", uniqueConstraints = #UniqueConstraint(columnNames = { "user_user", "role" }))
public class Role implements Serializable
{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne(targetEntity = User.class, fetch = FetchType.LAZY)
private User user;
private String role;
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
public User getUser()
{
return user;
}
public void setUser(User user)
{
this.user = user;
}
public String getRole()
{
return role;
}
public void setRole(String role)
{
this.role = role;
}
}
This ends up creating the tables (as I specified the fields) so I can provide an SQL query to the configuration and create a realm. There's a lot of good documentation on this if you Google "j_security_check".
As to a group? A group sounds like a collection of roles to me--so it isn't a stretch to modify the query to a third table, or simply provide an enum.
(after reading this, the only clarification is that my roles are stored in an enum which contains the string value of the role, so roles.getValue() returns a string like "administrators".
I'm thinking
A User table
A Group table
A User_is_in_group link table
A Rights table.
A User_in_group_has_Rights table.
Then map all the links to the relevant fields in JPA.
I can do more detail, but maybe this is enough for you to create your entities, as it will also depend on what fields you want.
Here goes a example with three tables (user, group and user_group):
#Entity
#Table(name="user")
public class User implements Serializable{
private static final long serialVersionUID = 1L;
private Long id;
private String name;
private String email;
private String password;
private List<Grupo> groups; //-> a lot of rules and permissions
public Usuario(){
}
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Column
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
#Column
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
/** Here is the third table **/
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name="user_group", joinColumns = #JoinColumn(name="user_id"),
inverseJoinColumns = #JoinColumn(name="group_id"))
public List<Grupo> getGroups() {
return groups;
}
public void setGroups(List<Grupo> groups) {
this.groups = groups;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Usuario other = (Usuario) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}
//////////////////////
#Entity
#Table(name="group")
public class Group {
private Long id;
private String name;
private String description;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Grupo other = (Grupo) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}