I have the following two classes.
School has many TestTakers
#Entity
#Table(name = "school")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class School extends BaseModel {
#Column(name = "name")
private String name;
#OneToMany(mappedBy = "school")
// #JsonManagedReference <<<<< If not commented out, then error
private Set<TestTaker> testTakers;
//getter setters
}
// TestTaker.java
#Entity
#Table(name = "test_taker")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class TestTaker extends BaseModel {
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#ManyToOne
#JoinColumn(name = "school_id")
#JsonBackReference("school_testTaker")
private School school;
//getters setters
}
Can anyone explain why #JsonManagedReference cannot be annotated on a collection? I would get an error saying Jackson cannot handle managed/back reference. How exactly does #JsonManagedReference work with #JsonBackReference in common DB relationships One-to-one, One-to-many, Many-to-one
I have read the documentation, still don't quite understand what Jackson is trying to achieve
Related
I'm having a hard time getting Spring Data to persist the values into an XREF Table. I'm attempting to talk to an existing DB so i cannot change the schema which would have made this easier.
Classes
#Entity
#Table(name="user_type")
class UserType {
#Id
#Column(name="name")
private String name;
}
#Entity
#Table(name="user_role")
class UserRole {
#Id
#Column(name="name")
private String name;
}
#Entity
#Table(name="company")
class Company{
#Id
#Column(name="id")
private UUID id;
#Column(name="name")
private String name;
}
#Entity
#Table(name="user")
class User {
#Id
#Column(name="id")
private UUID id;
#Column(name="email")
private String email;
#ManyToOne
#JoinTable
private UserType userType;
//not sure what to do here or which JoinTable/ManyToOne/Etc
private UserCompanyAccess userCompanyAccess;
}
#Entity
#Table(name="user_company_access")
class UserCompanyAccess {
#EmbeddedId
private UserCompanyAccessId userCompanyAccessId;
// not sure of relationships here either
private User user;
private Company company;
private UserRole userRole;
#Embeddable
static class UserAccessCompanyId implements Serializable {
#Column(name="id")
private UUID id;
}
}
I have tried many different combinations of #JoinColumns specifying the user(id) and userAccessCompany(user_id) as well with company. The code compiles but at runtime hibernate either throws an error saying company_id not provided or other random exceptions regarding trying to compare uuid to character varying etc which was really weird. Any help would be appreciated. I have done many #OneToMany/#ManyToOne/#ManyToMany but somehow never through spring data with an XREF table where the PK is not a composite of the 2 joining tables. That's what is throwing me off. Otherwise the #EmbeddedId would be the combination of the two.
The dark brown section of the spreadsheet is confusing, because it suggests there's a CompanyUser table that you haven't mentioned elsewhere. Is that an issue?
Regardless, it's a shame you can't adjust the schema, because this design has a lot of flaws. However, it should still be possible to use it. I'm a little stale on Java and Spring/Boot, and I don't have a useful way to test them easily, but you may have better luck with these:
#Entity
#Table(name="user")
class User {
#Id
#Column(name="id")
private UUID id;
#Column(name="email")
private String email;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_type", table="user_type", referencedColumnName = "name")
private UserType userType;
}
#Entity
#Table(name="user_type")
class UserType {
#Id
#Column(name="name")
private String name;
}
#Entity
#Table(name="user_role")
class UserRole {
#Id
#Column(name="name")
private String name;
}
#Entity
#Table(name="company")
class Company{
#Id
#Column(name="id")
private UUID id;
#Column(name="name")
private String name;
}
#Entity
#Table(name="user_company_access", uniqueConstraints = {
#UniqueConstraint(columnNames = { "user_id", "company_id" })
})
class UserCompanyAccess {
#Id
#Column(name="id")
private UUID id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "role", table="user_role", referencedColumnName = "name")
private UserRole userRole;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id", table="user", referencedColumnName = "id")
private User user;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "company_id", table="company", referencedColumnName = "id")
private Company company;
}
Explanation: The user_company_access table is where everything ultimately gets tied together. It's designed such that any particular combination of user and company to be unique, and #UniqueConstraint enables that in the code; you don't really need an embeddable object for that.
I'm setting up spring security, yet when I define a #OneToMany relationship I get the error:
Use of #OneToMany or #ManyToMany targeting an unmapped class: loginApi.users.Users.roles[Security.Roleinfo]
I've already tried most of the answers on here,
yes, I am importing from javax.persistance
yes, #Entity is on top of each class
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "users")
public class Users {
#Id
#Column(name="username")
private String username;
private String firstname;
private String lastname;
private int curreventid;
private String email;
private String password;
private int points;
private int phone;
// problem part
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name = "usersrole", joinColumns = {#JoinColumn(name = "username")}, inverseJoinColumns = {#JoinColumn(name = "roleid")})
private Set<Roleinfo> roles;
}
Here is the roleinfo class:
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "roleinfo")
public class Roleinfo {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int roleid;
private String roletitle;
}
right now I'm trying to join my usersrole table which has two columns containing the username and that user's role (roleid) with the user table.
any help would be appreciated!
Thanks #JB Nizet, after reading the docs I realized my security package wasn't under my springbootapp package, meaning the user class was never scanned for the #Entity flag.
I am working on hibernate and tying to associate mapping with #OneToMany relationship with composite key.
Following are the entities that currently my using .
#Embeddable
#Getter
#Setter
public class AddressKey implements Serializable {
private static final long serialVersionUID = -307823488229761699L;
#Column(name = "id")
private Long id;
#Column(name = "city")
private Long city;
#Column(name = "locale")
private String locale;
#Column(name = "type")
private String type;
#ManyToOne
#JoinColumn(name="id")
private Person person;
}
#Entity
#Table(name = "address", schema = "test")
#Setter
#Getter
public class AddressHistory {
#EmbeddedId
private AddressKey key;
#Column(name = "active")
private boolean active;
#Column(name = "current")
private boolean current;
}
#Entity
#Table(name = "person", schema="test")
#ToString
public class Person {
#Id
#Column(name = "id")
private Long id;
#OneToMany(mappedBy="key.person", fetch=FetchType.EAGER, cascade=CascadeType.ALL)
private Set<AddressHistory> addressHistory;
}
But when I am trying to run this program it gives me following error.
repeated column in mapping for entity AddressHistory.
Someone help me to fix this what's wrong in this mapping.
Thanks in advance
You repeated columns. Remove #JoinColumn(name="id") in AddressKey since you already have one column with the same name or rename it to something else and more maintainable like person_id.
I have two objects. The company that can have multiple nested addresses.
#Entity
#Data
#Table(name = "company")
public class Company {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#Column(name = "phone")
private String phone;
#OneToMany(mappedBy = "company", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private List<Address> addresses;
}
Address class looks like this:
#Data
#Entity
#Table(name = "address")
#ToString(exclude = "company")
public class Address {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name = "postal_code")
private String postalCode;
#Column(name = "city")
private String city;
#Column(name = "street")
private String street;
#JsonIgnore
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "company_id")
private Company company;
}
I want somehow if it's possible, make a dynamic query that searches through the nested collection property. I made a search method which uses example matcher but the result is wrong. Every time I got everything from DB, not only company with address postal code that I'm looking for.
My search method looks like this:
#PostMapping("/search")
public List<Company> search(#RequestBody final Company company){
return companyRepository.findAll(Example.of(company,
ExampleMatcher.matchingAny()
.withIgnoreNullValues()
.withIgnorePaths("id")
.withStringMatcher(ExampleMatcher.StringMatcher.STARTING)));
}
In my database, I have two objects and this is the result of the search:
As you can see I received everything from DB instead of the only first company which address postal code starts with 1.
Hi you can use Specification<T>
https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/
For this you need to extend from interface JpaSpecificationExecutor:
public interface UserRepository extends JpaRepository<User> ,JpaSpecificationExecutor<User>{
}
And you also need to implement your custom Specification<T>
And then you can use repository.findAll(your impleneted Specification);
Spring docs :
https://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/repository/JpaSpecificationExecutor.html
I think this is helpful.
I have a very large json to store and I divided that into following five entities and trying to store to h2 database using spring-data-jpa,inserting is working fine into database, but while fetching A object with A primary key Id, I am getting stackoverflow error, because there is circular dependency.
could someone help me to figure out what is the issue.
Top class
#Entity
#Table(name = "a")
#Data
public class A{
#Id
#Column(name = "a_id")
private String id;
#Column
private String name;
#Column
private String name2;
#Column
private String name3;
#Column
private String name4;
#Column
private String name5;
#OneToMany(cascade = CascadeType.ALL,mappedBy = "a",fetch =
FetchType.EAGER)
#JsonManagedReference
private List<B> b;
}
Second class
#Entity
#Table(name = "b")
#Data
public class B{
#Id
#Column(name = "bname")
private String bname;
#Column
private String bVersion;
#OneToMany(cascade = CascadeType.ALL,mappedBy = "b")
#JsonManagedReference
private List<C> cs;
#ManyToOne
#JoinColumn(name = "a_id")
#JsonBackReference
private A a;
}
Third class
#Entity
#Data
public class C{
#Id
#Column(name = "cname")
private String cName;
#Column
private String cVersion;
#OneToMany(cascade = CascadeType.ALL,mappedBy = "c")
#JsonManagedReference
private List<D> ds;
#ManyToOne
#JoinColumn(name = "bname")
#JsonBackReference
private B b;
}
Fourth class
#Entity
#Data
public class D{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="d_id")
private long id;
#Column
private String dName;
#Column
private String dName2;
#ElementCollection
#Column
private List<String> dNames;
#OneToMany(cascade = CascadeType.ALL,mappedBy = "d")
#JsonManagedReference
private List<E> e;
#ManyToOne
#JoinColumn(name = "cname")
#JsonBackReference
private C c;
}
Fifth class
#Entity
#Data
public class E{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "e_id")
private long id;
#Column
private String ename;
#Column
private String eName2;
#ManyToOne
#JoinColumn(name = "e_id")
#JsonBackReference
private E e;
}
I also faced the same problem and spent the whole day. Finally, I found its problem with the toString method generated by Lombok using #Data annotation.
Solution:
Override, toString method and write your own implementation. If you do not want to use toString then use #Getter and #Setter instead of #Data.
Why
Note: This occurs with bi-directional relationship.
Lets say I have two entity and having bi-directional relationship.
#data
Entity1{
#oneToMany
public List<Entity2> entity2s;
//Added by lombok while using #Data
#Generated
public String toString() {
return "entity2s=" + this.getEntity2s() + ")";
}
}
#data
Entity2{
#ManytoOne
public Entity1 entity1;
//Added by lombok while using #Data
#Generated
public String toString() {
return "entity1=" + this.getEntity1() + ")";
}
}
In above example, toString()(called by JPA) of Entity1 calles toString() of Entity2 and toString() of Entity2 calls toString() of Entity1. And that is how circular reference is building.
Note: The same goes to hashCode method.
Here is a some reference links,
https://github.com/rzwitserloot/lombok/issues/1007
https://interviewbubble.com/stackoverflow-tostring-method-when-using-lombok/