hibernate criteria if collection contains collection - database

I have a Priv class
#Entity
#Table(name = "PK_PRIVS", schema = "dbo")
public class Priv implements java.io.Serializable{
private static final long serialVersionUID = 1L;
private String code;
private String name;
private String description;
private PrivType type;
//...
}
and a Report class which has many to many relation with Priv and contains Set of associated Privs - privs.
#Entity
#Table(name = "REPORT", schema = "dbo")
public class Report implements java.io.Serializable {
//...
private Set<Priv> privs = new HashSet<Priv>(0);
//...
#JsonIgnore
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "REPORT_PK_PRIVS", schema = "dbo", joinColumns = { #JoinColumn(name = "REPORT_ID") }, inverseJoinColumns = { #JoinColumn(name = "PK_PRIVS_CODE") })
public Set<Priv> getPrivs() {
return this.privs;
}
public void setPrivs(Set<Priv> privs) {
this.privs = privs;
}
}
Now I have a Set of Strings, which are codes of Priv classes (code is Primary Key in Priv).
Set<String> privsCodesSet; //set of codes of Priv classes
I need a criterion which allow me to find that Reports, which all codes from its Priv set contains in privsCodesSet. For example if I have privsCodeSet = {"code1", "code2"}
Report with privs with codes {"code1"" should be in result, but
Report with privs with codes {"code1", "code2", "code3"} should not.
I also have class which is join of Priv and Report, but I'm not sure if it's help.

This code should work
Criteria reportPrivCriteria = currentSession()
.createCriteria( Report.class, "r");
reportPrivCriteria.createAlias("privs", "p");
reportPrivCriteria.add(Restrictions.in(p.code, privsCodeSet));
Do you have something like this on your Priv class?
private Set<Report> reports;
// ...
#ManyToMany(mappedBy="privs")
public Collection<Report> getReports() {
return reports;
}

Related

How to update a List of Users in the User class Spring Boot

I have a Java User class, a user can have friends (List<User>). By default, Hibernate create two tables : USER and USER_FRIENDS(USER_ID,FRIENDS_ID)
The problem is when I change friends in my code and that I save(user), spring add the new friends but don't remove in the database the friends removed from the array list.
#Entitypublic class User implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String pseudo;
private String password;
private String email;
private Gender gender;
#Lob
private byte[] avatar;
private String description;
private Date birthdate;
#ManyToMany(cascade = CascadeType.ALL)
private List<Game> favoriteGames = new ArrayList<>();
#OneToMany( cascade = CascadeType.ALL)
private List<User> friends = new ArrayList<>();
I tried #ManyToMany, #OneToMany, cascade = CascadeType.ALL
Basically, first I would advise that you take special care with your equals and hashCode implementation in your entities. You did not show us that, but it should be something like this in your User.java:
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof User)) {
return false;
}
User other = (User) o;
return id != null && id.equals(other.getId());
}
#Override
public int hashCode() {
return getClass().hashCode();
}
Those are very important, especially when working with entities in collections.
Secondly, a connection between a User and his Friends (other Users) should be modeled as Many-to-Many, because:
every user can be a friend to MANY of other users
every user can have any number of friends, in other words MANY friends
And I would model this connection like this:
#ManyToMany
#JoinTable(name = "user_friends", joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "friend_user_id"))
private Set<User> friends = new HashSet<>();

How to fetch data from database using hibernate ManyToMany

I'm using hibernate with manyToMany relation and I want to display data from database
Thank you in advance.
I get this errors:
database :
Here is the code :
Class EnseignerId :
#Embeddable
public class EnseignerId implements Serializable {
//id professeur
#Column(name="professeur_code")
private int code;
//id matiere
#Column(name="matiere_reference")
private String reference;
public EnseignerId() {
super();
}
//getters and setters...
Class Enseigner :
#Entity
#Table(name="Enseigner")
public class Enseigner {
#EmbeddedId
private EnseignerId id = new EnseignerId();
//id prof
#ManyToOne
#MapsId("code")
private Professeur professeur;
//id matiere
#ManyToOne
#MapsId("reference")
private Matiere matiere;
#Column(name="heures")
private int heures;
//constructor getters and setters...
Class Professeur:
#Entity
#Table(name="professeur")
public class Professeur {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="code")
private int code ;
#Column(name="nom")
private String nom;
#Column(name="prenom")
private String prenom;
...
#OneToMany(
mappedBy="professeur",
cascade = CascadeType.ALL,
orphanRemoval = true)
private List<Enseigner> matieres; //List<Association> Class; //I followed a tutorial
//constructor getters and setters...
public List<Enseigner> getMatieres() {
return matieres;
}
Class Matiere :
#Entity
#Table(name="matiere")
public class Matiere {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="reference")
private String reference;
#Column(name="description")
String description;
#Column(name="volume")
int volume;
#OneToMany(
mappedBy= "matiere",
cascade = CascadeType.ALL,
orphanRemoval = true)
private List<Enseigner> professeurs;
//constructor getters and setters...
getProfesseur() method :
public Professeur getProfesseur(int code) {
SessionFactory sessionFactory = getSessionFactory(); //static method
Session session = sessionFactory.openSession();
Professeur professeur = null;
try {
session.getTransaction().begin();
System.out.println("------------Calling getProfesseur()----------");
professeur = session.get(Professeur.class, code);
if(professeur != null) {
System.out.println(professeur);
}else {
throw new DAOException( "CODE INVALIDE!" );
}
}
catch(Exception e ) {
System.out.println(e.getMessage());
}
finally {
session.close();
}
return professeur;
}
Saving data and getting professors who don't have an Matiere work. but getting Matiere or professeur whose primary key exists in the join table Enseigner generate errors when I do something like :
Professeur prof =profDAO.getProfesseur(2); //*generates errors* //the professor with id=2 exists in database
System.out.println(prof);
List<Enseigner> enseigner = prof.getMatieres(); //*generates errors*...
List<Matiere> matieres = new ArrayList<>();
for(Enseigner ens : enseigner) {
matieres.add(ens.getMatiere());
System.out.println(ens);
}
/*for(Matiere mat : matieres) {
System.out.println(mat);
}*/
This problem has nothing to do with Hibernate. Please inspect the stack trace carefully: your Enseigner.toString() calls Professeur.toString() which in turn calls Enseigner.toString() again and so on.
I notice this problem more and more these days when people blindly use Lombok with its #Data (which should almost never be used), #ToString and #EqualsAndHashCode. These generate respective methods that include all fields!
You need to remove these annotations or set them up so that they use only the fields that you really need. Most of the time your equals() and hashCode() are not needed when you write web apps with ORM. Hibernate ensures you don't have 2 instances of the same entity.
On the other hand toString() can be useful, but we shouldn't include all fields in it - just the ones that are helpful in identifying the entity.
You have cyclic reference. You need exclude field professeurs and matieres by #JsonIgnoreProperties

Hibernate: ManyToOne generating field raw(255)

I recently upgraded from hibernate-core 4.1.7 to 5.0.9 and Have problem with this code:
#ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
#JoinColumn(name = "FK_AAA", foreignKey = #ForeignKey(name = "CS_BBB"))
#org.hibernate.annotations.Index(name = "IDX_CCC", columnNames = "FK_DDD")
private ImportData importData;
This generate correct foreign columns pointing to the defining class, but also generating a column on the same class:
IMPORTDATA RAW(255)
Why is this raw(255) column generated ? I think it was not generated with Hibernate-core 4.1.7
any idea ?
Update 1: here is longer code fragments:
#MappedSuperclass
#Access(AccessType.PROPERTY)
public abstract class BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public abstract Long getId();
}
#Entity
#Table(name = "IMPORT_DATA", uniqueConstraints = {
#UniqueConstraint(name = "UC_IMP_BID", columnNames = {"BUSINESS_ID"})
}, indexes = {
#Index(name = "IDX_IMP_DGXML_ID", columnList = "FK_DGXML_ID"),
#Index(name = "IDX_IMP_IMPXML_ID", columnList = "FK_IMPXML_ID")
})
public class ImportData extends BaseEntity {
#Id #GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() { return id; }
// ...
}
#Entity(name = "MUTATION")
#Table(name = "MUTATION")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "TYPE", discriminatorType = DiscriminatorType.STRING)
#SequenceGenerator(name = "mutationsSeq", sequenceName = "MUTATIONS_SEQUENCE", allocationSize = 1)
public abstract class Mutation extends BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "mutationsSeq")
private Long id;
#ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
#JoinColumn(name = "FK_IMP_ID", foreignKey = #ForeignKey(name = "CS_MUT_IMP_ID"))
#org.hibernate.annotations.Index(name = "IDX_MUT_IMP_ID", columnNames = "FK_IMP_ID")
protected ImportData importData;
}
#Entity(name="XXX")
#DiscriminatorValue("XXX_DISC")
public class XXX extends Mutation {
// ...
}
I found an answer on Mapping composite key with Hibernate produces a raw field in Oracle:
I was mixing annotations on fields and methods. I also had #Id on an abstract superclass, and a redefinition on a derived class.
Fixing theses two elements, cleaning DB and regenerating in "create" ddl mode proved that the fix was no longer generating RAW field type.
Thanks for all your helps!

Room database with one-to-much relation

I have 2 Entities: Employee and Specialty.
Every Employee can have some Specialties.
POJOs are generated.
#Entity(indices = {#Index(value = {"f_name", "l_name", "birthday",
"avatarLink"}, unique = false)}, inheritSuperIndices = true)
public class Employee implements Serializable {
#PrimaryKey(autoGenerate = true)
private int employeeId;
private String f_name;
private String l_name;
private String birthday;
#Ignore
private int age;
private String avatarLink;
#Embedded
private List<Specialty> specialty;
private final static long serialVersionUID = -8824149947485321362L;
#Ignore
public Employee() {
}
public Employee(int employeeId, String f_name, String l_name, String
birthday, String avatarLink, List<Specialty> specialty) {
this.employeeId = employeeId;
this.f_name = f_name;
this.l_name = l_name;
this.birthday = birthday;
this.avatarLink = avatarLink;
this.specialty = specialty;
}
public int getEmployeeId() {
return employeeId;
}
public void setEmployeeId(int employeeId) {
this.employeeId = employeeId;
}
And some more setters\getters...
And Specialty
#Entity
public class Specialty implements Serializable {
#PrimaryKey
private int specId;
private String specName;
private final static long serialVersionUID = 4288061416169200241L;
public Specialty(int specId, String specName) {
this.specId = specId;
this.specName = specName;
}
#Ignore
public Specialty() {
}
public int getSpecId() {
return specId;
}
And some more setters\getters...
I have this error:
error: Entities and Pojos must have a usable public constructor. You can have an empty constructor or a constructor whose parameters match the fields (by name and type).
I check so many questions and read docs, but it not helps me. Thank you
you should add #Ignore to serialVersionUID fields.
In view of Room, it's just another column.
#Ignore
private final static long serialVersionUID = 4288061416169200241L;

JPA Datanucleus showing old data that is no longer in datastore

I have two entities: Account, Home. The relationship is such
#Entity
public class Account implements java.io.Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Key userId;
private String data;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<Home> homes = new ArrayList<Home>();
public Account() {
}
public Account(String data) {
this. data = data;
}
public Account(String data, List<Home> homes) {
super();
this. data = data;
this.homes = homes;
}
public List<Home> getHomes() {
return homes;
}
public void setHomes(List<Home> homes) {
this.homes = homes;
}
}
//HOME
#Entity
public class Home implements java.io.Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Key key;
private long timestamp;
private long userId;
public Home(long latlong, long userId) {
Key key = KeyFactory.createKey(Home.class.getSimpleName(), latlong + "" + userId);
this.key = key;
this.userId = userId;
}
//getters and setters
}
The invariants are such that the latlong for a user never changes. Therefore, when I add a Home entity, if one already exists for said user, it is simply replaced in the datastore. So far so good. But I am getting a problem for the following user case:
Say user X edit his home data 6 times. Sure enough when I look in the datastore, there is only one entry for Home and it contains the latest data. But after querying for Account using datanucleus, when I do getHomes().size() the result is 6. Apparently datanucleus is caching every single edit as an individual entity. It’s a mystery to me. I am logging the code so I am seeing it happening: For the exact same key (I use a for-loop), I am getting each iteration/edit of the entity. How do I keep this from happening? The datastore clearly shows one entity for the key. I just want that one entity: no historical list.
My datanucleus/jpa getById is
#Override
public T getById(Long id) {
EntityManager mgr = getEntityManager();
try {
return null == id ? null : mgr.find(type, id);
} finally {
mgr.close();
}
}
Still baffled per the root cause of the problem, I replaced List with Set and my problem is now solved.

Resources