Spring JPA fetch nested entities - database

I have 3 entity classes with relations as below:
class SocietyData {
#OneToMany(mappedBy = "societyData")
private List<SubsectionData> subsectionDataList = new ArrayList<>();
}
class SubsectionData {
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "society_id", nullable = false)
private SocietyData societyData;
#OneToMany(mappedBy = "subsectionData")
private List<BasementData> basementDataList = new ArrayList<>();
}
class BasementData {
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "subsection_id", nullable = false)
private SubsectionData subsectionData;
}
I am trying to fetch society data information by using entity graph:
#Repository
public interface SocietyRepo extends JpaRepository<SocietyData, Long> {
#EntityGraph(attributePaths = {"subsectionDataList", "subsectionDataList.basementDataList"})
Optional<SocietyData> findById(long id);
}
I am not getting proper society data object and getting cant parse json exception after taking so long time sometimes!
How to solve this?
Thanks in Advance.

Related

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!

Updating multiple tables when saving entity Spring MVC Angular

I have a problem with saving entity with references to database using
Spring MVC and AngularJS.
My entities:
Entity
#Table(name = "comment")
public class Comment {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name = "id", nullable = false)
private Long id;
#Column(name = "creation_date", nullable = false)
private Date creationDate;
#Column(name = "comment", nullable = false)
private String comment;
#ManyToOne
#JoinColumn(name = "article", nullable = false)
private Article article;
#ManyToOne
#JoinColumn(name = "user", nullable = false)
private User user;
}
#Entity
#Table(name = "article")
public class Article {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", nullable = false)
private Long id;
#ManyToOne
#JoinColumn(name="user", nullable=false)
private User user;
...
}
How can I save new Article but at the same time add new entity to Comment table?
How can two updates be performed in one transaction?
How sholud I connect request from angular with controller, and how sholud they look?
Angular:
$http({
url : ..../new,
method : POST,
data : ?
})
#RestController
#RequestMapping(value = "/new", method = RequestMethod.POST)
public Article addArticle(#RequestBody Article article, ?) {
article.setId(null);
return articleService.save(article);
//but how to save comment?
}
Thank You!

Collection null in AngularJS + Spring Data JPA #OneToMany #ManyToOne

I have a bidirectional relationship.
This is my entity factura:
#Entity
#Table(name = "T_FACTURA")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Factura implements Serializable {
...
#OneToMany(mappedBy = "factura")
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Facturaservicio> facturaservicios = new HashSet<>();
...
#Override
public String toString() {
//all attributes except facturaservicios
}
}
This is my entity facturaservicio:
#Entity
#Table(name = "T_FACTURASERVICIO")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Facturaservicio implements Serializable {
...
#ManyToOne
private Factura factura;
...
#Override
public String toString() {
//all attributes except factura
}
}
This is my REST controller
#RestController
#RequestMapping("/app")
public class FacturaResource {
private final Logger log = LoggerFactory.getLogger(FacturaResource.class);
#Inject
private FacturaRepository facturaRepository;
#RequestMapping(value = "/rest/facturas",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public List<Factura> getAll() {
log.debug("REST request to get all Facturas");
return facturaRepository.findAll();
}
And this is my AngularJS controller:
$http.get('app/rest/facturas').
success(function (data, status, headers, config) {
console.log(JSON.stringify(data));
});
Why my collection is null in the AngularJS controller? How can I access to collection?
When JHipster creates a entity with OneToMany - ManyToOne relationship makes that the first entity (factura) has a list of the second entity (facturaservicios) but it not say the type of relation.
So the solution is add fetch = FetchType.EAGER in the #OneToManyRelation.
#OneToMany(mappedBy = "factura", fetch = FetchType.EAGER)
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Facturaservicio> facturaservicios = new HashSet<>();
#ManyToOne
private Factura factura;
In the Factura entity, you need to remove the #JsonIgnore property in the following snippet:
#OneToMany(mappedBy = "factura")
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Facturaservicio> facturaservicios = new HashSet<>();

hibernate criteria if collection contains collection

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;
}

Resources