I have two tables Department and Employees. Department is parent of Employee and both are joined by department_id.
Department
#Entity
public class Department {
#Override
public String toString() {
return "Department [departmentId=" + departmentId + ", departmentName=" + departmentName + "]";
}
#Id
public Integer departmentId;
public String departmentName;
#OneToMany(mappedBy = "department",fetch=FetchType.LAZY)
public Set<Employee> employees;
}
Employee
#Entity
public class Employee {
#Override
public String toString() {
return "Employee [employee_id=" + employeeId + ", employee_name=" + employeeName + ", department="
+ department + "]";
}
#Id
public Integer employeeId;
public String employeeName;
#ManyToOne
#JoinColumn(name = "departmentId")
public Department department;
}
When I am trying to retrieve all department details it is creating a cyclic dependency and jackson is throwing the following error . So I would like to know how is this case handled where you need flexibility to access the child details from parent and access parent details from child.
2017-08-01 12:03:13.245 WARN 18197 --- [o-auto-1-exec-3]
.w.s.m.s.DefaultHandlerExceptionResolver : Failed to write HTTP message:
org.springframework.http.converter.HttpMessageNotWritableException: Could not
write JSON: Infinite recursion (StackOverflowError); nested exception is
com.fasterxml.jackson.databind.JsonMappingException:
I was able to achieve this solution using the following approach #JsonIgnoreProperties. By using this way i was able to fetch employee details in department and department level details in employees and avoiding infinite recursion
#JsonIgnoreProperties("department")
#OneToMany(mappedBy = "department",fetch=FetchType.EAGER)
public Set<Employee> employees;
#JsonIgnoreProperties("employees")
#ManyToOne
#JoinColumn(name = "departmentId")
public Department department;
You can use #JsonManagedReference and #JsonBackReference :
#JsonBackReference
public Department department;
and in Department Model
#JsonManagedReference
public Set<Employee> employees
It should work now :)
Yes this is expected, Jackson will iterate over your references and since the relation is bidirectional it will get stuck in an infinite operation.
To solve this you can use #JsonIgnore to ignore serializing one side of the relation to break the loop
#Entity
public class Employee {
#Override
public String toString() {
return "Employee [employee_id=" + employeeId + ", employee_name=" + employeeName + ", department="
+ department + "]";
}
#Id
public Integer employeeId;
public String employeeName;
#JsonIgnore
#ManyToOne
#JoinColumn(name = "departmentId")
public Department department;
}
Related
The table was not being created for the following model despite following the correct procedure
Model
#AllArgsConstructor
#NoArgsConstructor
#Data
#Entity
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
Integer pid;
String name;
String desc;
double price;
}
So I was creating an entity class for JPA where there was a field name desc. I was using MySQL database. But for some reason, I was getting the following error.
The model
#AllArgsConstructor
#NoArgsConstructor
#Data
#Entity
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
Integer pid;
String name;
String desc;
double price;
}
Later I changed the field name and the whole thing was working. The ORM was automatically creating the table.
The updated model that works
#AllArgsConstructor
#NoArgsConstructor
#Data
#Entity
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
Integer pid;
String name;
String description;
double price;
}
so i'm trying to insert an hardcoded member to my Members table. I'm using Spring Boot & JDBC on Eclipse.
This is my schema.sql:
CREATE TABLE Members
(
ID int not null,
LastName varchar(255) not null,
FirstName varchar(255) not null,
PhoneNumber integer not null,
created timestamp not null,
primary key(ID)
);
INSERT INTO MEMBERS (ID, LASTNAME, FIRSTNAME,PHONENUMBER, CREATED)
VALUES(1001, 'Max', 'Mad', 0547547547, sysdate());
i got a findAll method in a DAO class:
public List<Member> findAll(){
return jtemp.query("select * from members", new BeanPropertyRowMapper<Member>(Member.class));
}
when i run it, it returns:
[Member [id=0, firstName=Mad, lastName=Max, phoneNumber=547547547, created=2017-10-31 18:57:21.606]]
As you can see the ID wasn't inserted for some reason.
my Member class is like this:
public class Member {
private long id;
private String firstName;
private String lastName;
private long phoneNumber;
private Date created;
public Member(long id, String firstName, String lastName, long phoneNumber, Date created) {
super();
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.phoneNumber = phoneNumber;
this.created = created;
}
public long getUserId() {
return id;
}
public void setUserId(long userId) {
this.id = userId;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public long getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(long phoneNumber) {
this.phoneNumber = phoneNumber;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
#Override
public String toString() {
return "Member [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", phoneNumber="
+ phoneNumber + ", created=" + created + "]";
}
}
How can i fix it?
I tried to inserted different numbers, but i always get a zero in the log.
Thanks
Column names of the query must match the setters in the target object.
Your query has a column named id but there is no setId method. You should either rename setUserId to setId or in the query give the alias user_id to id column.
From BeanPropertyRowMapper documentation:
Column values are mapped based on matching the column name as obtained from result set metadata to public setters for the corresponding properties. The names are matched either directly or by transforming a name separating the parts with underscores to the same name using "camel" case.
I'm trying to do a 3 table Join Query with Spring data and I'm running into a query validation issue.
The exact error I get is:
Caused by: java.lang.IllegalArgumentException: Validation failed for query for method public abstract java.util.List com.somethinng.domain.subscriberCategoriesRepository.findByJoin()!
at org.springframework.data.jpa.repository.query.SimpleJpaQuery.validateQuery(SimpleJpaQuery.java:92)
at org.springframework.data.jpa.repository.query.SimpleJpaQuery.<init>(SimpleJpaQuery.java:62)
at org.springframework.data.jpa.repository.query.JpaQueryFactory.fromMethodWithQueryString(JpaQueryFactory.java:72)
at org.springframework.data.jpa.repository.query.JpaQueryFactory.fromQueryAnnotation(JpaQueryFactory.java:53)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$DeclaredQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:144)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:212)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:77)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.<init>(RepositoryFactorySupport.java:436)
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:221)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.initAndReturn(RepositoryFactoryBeanSupport.java:277)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:263)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:101)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1687)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1624)
... 39 more
On the Database side here are my three tables
create table subscribers(
id int auto_increment primary key,
email varchar(255),
unique (email));
create table categories (
id int auto_increment primary key,
source varchar(255) not null,
description varchar(255) not null);
create table subscriberCategories(
subscriber int not null,
source int not null,
primary key (subscriber,source), -- prevents dupes
constraint `fk_2user` foreign key (subscriber) references subscribers(id));
And here are my POJO's and Repositories
Subscribers
#Entity
#Getter
#Setter
public class Subscribers {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#NotNull
private String email;
public Subscribers() { }
public Subscribers(Integer id) {
this.id = id;
}
public Subscribers(String email, String description) {
this.email = email;
}
}
Categories
#Entity
#Getter
#Setter
public class Categories {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#NotNull
private String description;
#NotNull
private String source;
public Categories() { }
public Categories(Integer id) {
this.id = id;
}
public Categories(String source, String description) {
this.source = source;
this.description = description;
}
}
SubscriberCategories
#Entity
#Getter
#Setter
public class subscriberCategories {
#Id
#Column(name = "subscriber")
private Integer id;
#NotNull
private Integer source;
public subscriberCategories() {
}
public subscriberCategories(Integer subscriberId) {
this.id = subscriberId;
}
public subscriberCategories(Integer source, Integer subscriberId) {
this.source = source;
this.id = subscriberId;
}
}
Repositories
SubscriberRepository
#Repository
public interface SubscriberRepository extends CrudRepository<Subscribers, Integer> {
}
CategoriesRepository
#Repository
public interface CategoriesRepository extends CrudRepository<Categories, Integer> {
List<Categories> findById(Integer id);
Long deleteBySource(String source);
List<Categories> findBySource(String source);
}
subscriberCategoriesRepository
#Transactional
#Repository
public interface subscriberCategoriesRepository extends CrudRepository<subscriberCategories, Integer> {
#Query(value = "SELECT DISTINCT s.email as Subscriber, c.source as Source from Subscribers s" +
"Inner Join subscriberCategories sc on s.id = sc.subscriber" +
"Inner Join Categories c on sc.subscriber = s.id where s.email = 'xxxxx#gmail.com'")
List<subscriberCategories> findByJoin();
Lastly I have the following unit test which is throwing the error when I run it
#RunWith(SpringRunner.class)
#SpringBootTest
#EnableJpaRepositories(basePackageClasses = subscriberCategories.class)
#Transactional
public class subscriberCategoriesTest {
#Autowired
subscriberCategoriesRepository subscriberCategoriesRepository;
#Test
public void testLoadCategories() {
List<subscriberCategories> subscriberCategories = (List<subscriberCategories>) subscriberCategoriesRepository.findByJoin();
assertEquals("Should contain something", 1, subscriberCategories.size());
}
If someone give me a hand with this I would really appreciate it
Thanks
Using LINQ, is it possible to combine properties from both an object and a nested collection of that object into a new object? So for each item in the nested collection, I want to create a new object that has the nested object information coupled with the parent object's info.
Using a sample scenario, I'm trying to do something like this:
Teachers.Select(Function(item) New TeacherRecord() With
{.TeacherId = item.Id,
.TeacherName = item.Name,
.StudentID = ? ,
.StudentName = ?}).ToList()
Sample Classes
Public Property Teachers as List(of Teacher)
Public Class Teacher
Public Property ID as Integer
Public Property Name as String
Public Property Room as String
Public Property Students as List(of Student)
End class
Public Class Student
Public Property ID as Integer
Public Property Name as String
End Class
Public Class TeacherRecord
Public Property TeacherId as Integer
Public Property TeacherName as String
Public Property StudentId as Integer
Public Property StudentName as String
End Class
You need to use SelectMany, I don't know much about VB but this is how you do it in C#:
List<TeacherRecord> records = teachers.SelectMany(t => t.Students, (t, s) =>
new TeacherRecord { TeacherId = t.ID,
TeacherName = t.Name,
StudentId = s.ID,
StudentName = s.Name }).ToList();
you will need to rethink your TeacherRecord relationship to a Teacher Or Student - now it is unclear, but generally you can combine then for your ViewData and code will look like this:
void Main(){
List<Teacher> teacher = new List<Teacher>();
List<Student> student = new List<Student>();
student.Add(new Student{ID=1,Name="Tom"});
student.Add(new Student{ID=2,Name="Jerry"});
teacher.Add(new Teacher{ID=1
,Name="John"
,Room = "Room A"
,Students = student});
var combined = (from t in teacher
select t).ToList();
}
// Define other methods and classes here
public class Teacher
{
public int ID { get; set; }
public string Name { get; set; }
public string Room { get; set; }
public List<Student> Students { get; set; }
}
public class Student
{
public int ID { get; set; }
public string Name { get; set; }
}
public class TeacherRecord
{
public int TeacherId { get; set; }
public string TeacherName { get; set; }
public int StudentId { get; set; }
public string StudentName { get; set; }
}
and result will be something like this:
I have 2 public classes; Person and Engineer. Engineer is inherited from Person class.
Now in main() I have a person object say
Person abc = new Person();
and I am trying to convert "abc" to Engineer i.e.
Engineer xyz = (Engineer) abc;
Question: Is this legal? My understanding is I cannot do it because "abc" might have different attributes.
Code:
public class Person {
private String firstname;
private String lastname;
private String gender;
public Person(String first, String last, String gen) {
firstname = first;
lastname = last;
gender = gen;
}
public void setFirstName(String name) {
firstname = name;
}
public void setLastName(String name) {
lastname = name;
}
public void setGender(String gen) {
gender = gen;
}
public String getFirstName() {
return firstname;
}
public String getLastName() {
return lastname;
}
public String getGender() {
return gender;
}
public toString() {
return "firstname=" + firstname + "lastname=" + lastname + "gender=" + gender;
}
public class SoftwareEngineer extends Person {
public String teamname;
public String bestlanguage;
public SoftwareEngineer(String first, String last, String gen, String team, String lang) {
firstname = first;
lastname = last;
gender = gen;
teamname = team;
bestlanguage = lang;
}
public toString() {
return "firstname=" + firstname + "lastname=" + lastname + "gender=" + gender + "teamname=" + teamname + "bestlanguage=" + bestlanguage;
}
public void main() {
SoftwareEngineer aaron = new SoftwareEngineer('Aaron','Gottlieb','M','IPSupport','SQL');
Person andy = new SoftwareEngineer('Andy','Gardner','M','IP','Java');
Person pete = new Person("Pete", "G", "M");
Person personAaron = aaron;
SoftwareEngineer sePete = (SoftwareEngineer) pete;
SoftwareEngineer seAndy = (SoftwareEngineer) andy;
pete.teamname = "FooBar";
aaron.setLastName("Brian");
}
Every engineer is a person, but not every person is an engineer. Now translate it to your OO domain. Do you think you can always cast Person to Engineer? I.e. assume that every person is an engineer?
No, but you can ask person: are you an engineer?:
if(abc instanceof Engineer) {
Engineer xyz = (Engineer) abc;
}
But you don't always have to know that. You can ask every person about name, it doesn't matter whether that person is an engineer or not:
Person p = new Engineer();
p.getFirstName();