I've been trying to set up inheritance in my Spring boot project, but I failed to do so. I've tried using the superclass mappings, joined table, single table but still I think I'm missing something. Here is how the classes look like:
Person class:
#Entity
#MappedSuperclass
#Table(name = "person")
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id_person", nullable = false)
private Integer id;
#Column(name = "first_name", nullable = false, length = 200)
private String firstName;
#Column(name = "last_name", nullable = false, length = 200)
private String lastName;
#Column(name = "PESEL", nullable = false)
private Integer pesel;
#OneToOne(fetch = FetchType.LAZY, mappedBy = "person")
private Driver driver;
//setters and getters below
}
Driver class:
#Entity
#Table(name = "driver")
public class Driver {
#Id
#Column(name = "id_driver", nullable = false)
private Integer id;
#MapsId
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_driver")
private Person person;
#Column(name = "birth_date", nullable = false)
private LocalDate birthDate;
#Column(name = "license", nullable = false, length = 200)
private String license;
#OneToMany(mappedBy = "idDriver")
private Set<Ride> rides = new LinkedHashSet<>();
//setters and getters below
}
Here's how it is joined in the database (mysql):
I would be very thankful if you could at least point me in the right direction (like which inheritance type will suit this simple case the best)
First remove the #Entity and #Table annotations, as well as the relationship, from your superclass:
#MappedSuperclass
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id_person", nullable = false)
private Integer id;
#Column(name = "first_name", nullable = false, length = 200)
private String firstName;
#Column(name = "last_name", nullable = false, length = 200)
private String lastName;
#Column(name = "PESEL", nullable = false)
private Integer pesel;
//setters and getters below
}
Secondly, remove the duplicated id column and remove the relationship between the mapped superclass and your derived classes, and actually extend the superclass:
#Entity
#Table(name = "driver")
public class Driver extends Person{
#Column(name = "birth_date", nullable = false)
private LocalDate birthDate;
#Column(name = "license", nullable = false, length = 200)
private String license;
#OneToMany(mappedBy = "idDriver")
private Set<Ride> rides = new LinkedHashSet<>();
//setters and getters below
}
Related
I am using spring boot application. The application has one POST endpoint. There are many bidirectional entities in the application.
I tried to save the Questionnaire (one of the entity ) I get the following error on the POSTMAN.
{ "message": "Content type 'application/json;charset=UTF-8' not supported",
"httpStatus": "INTERNAL_SERVER_ERROR"}
And on the application console I get the following error.
[nio-8080-exec-2] .c.j.MappingJackson2HttpMessageConverter : Failed to evaluate Jackson deserialization for type [[simple type, class com.QuestionnaireDTORequest]]: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot handle managed/back reference 'defaultReference': back reference type (`java.util.Set<com.entity.Questionnaire>`) not compatible with managed type (com.entity.Questionnaire)
The Questionnaire entity is as follows:
public class Questionnaire {
#Id
#Column(name = "id")
#GeneratedValue
private UUID id;
#Column(name = "description")
#NotNull
private String description;
#Column(name = "created_date")
#NotNull
private LocalDate createdDate;
#Column(name = "approval_status")
#NotNull
private String approvalStatus;
#Column(name = "version")
#NotNull
private String questionnaireVersion;
#Column(name = "is_active")
#NotNull
private boolean isActive = false;
#JsonManagedReference
#ManyToMany
#JoinTable( name = "questionnaire_question",
joinColumns = #JoinColumn(name = "questionnaire_id"),
inverseJoinColumns = #JoinColumn(name = "question_id"))
private Set<Question> questionSet = new HashSet<>();
#OneToMany(mappedBy = "questionnaire")
private Set<AnsweredQuestionnaire> answeredQuestionnaireSet = new HashSet<>();
}
public class AnsweredQuestionnaire {
#Id
#Column(name = "id")
#GeneratedValue
private UUID id;
#Column(name = "comment")
private String comment;
#ManyToOne
#JoinColumn(name = "questionnaire_id")
private Questionnaire questionnaire;
#OneToOne
private Process process;
#ManyToMany
#JoinTable( name = "answer",
joinColumns = #JoinColumn(name = "answered_questionnaire_id"),
inverseJoinColumns = #JoinColumn(name = "possible_answer_id"))
private Set<PossibleAnswer> possibleAnswerSet = new HashSet<>();
}
public class Question {
#Id
#Column(name = "id")
#GeneratedValue
private UUID id;
#Column(name = "text")
#NotNull
private String text;
#Column(name = "weight")
#NotNull
private Integer weight;
#Column(name = "minimal_bcm_class")
private Integer minimalBcmClass;
#Column(name = "comment")
private String comment;
#JsonBackReference
#ManyToMany(mappedBy = "questionSet")
private Set<Questionnaire> questionnaireSet = new HashSet<>();
#ManyToMany(mappedBy = "questionSet")
private Set<PossibleAnswer> possibleAnswerSet = new HashSet<>();
}
I am not sure what is causing this error, any suggestion will be helpful.
#PostMapping(
produces = MediaType.APPLICATION_JSON_VALUE ,
consumes = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_JSON_UTF8_VALUE}
)
public String createQuestionnaire(#RequestBody QuestionnaireDTORequest questionnaireDTORequest){
Questionnaire questionnaire = mapToQuestionnaire(questionnaireDTORequest);
Questionnaire createdQuestionnaire = questionnaireService.createQuestionnaire(questionnaire);
if(createdQuestionnaire != null)
return "Questionnaire created successfully";
else
return "Questionnaire cannot be created";
}
The POSTMAN request is as follows
{
"description": "Third questionnaire",
"createdDate": "2022-06-23",
"approvalStatus": "Approved",
"questionnaireVersion": "V1",
"isActive": false,
"questionSet": [
{
"text": "Question text",
"possibleAnswerSet": []
},
{
"text": "Question text",
"possibleAnswerSet": []
}
]
}
Please let me know if you need any other information.
I have problem with deleting datas in my Tables.
CategoryModel:
#Entity
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Table(name = "Category")
public class CategoryModel {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
private Long category_id;
#Column(name = "CategoryName")
private String cateGoryName;
#Column(name = "Image")
#Lob
private String image;
#OneToMany(mappedBy = "categoryModel", cascade = CascadeType.ALL, orphanRemoval = true)
private List<ProductModel> productModels = new ArrayList<>();
}
ProductModel:
#Entity
#Getter
#Setter
#Table(name = "Products")
public class ProductModel {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
private Long product_id;
#Column(name = "ProductName")
#Lob
private String productName;
#Column(name = "ShortName")
private String shortName;
#Column(name = "Price")
private int price;
#Column(name = "Slider")
private Boolean slider;
#Column(name = "SpecialOffer")
private Boolean specialOffer;
#Column(name = "NewPrice")
private int newPrice;
#Column(name = "ShortDesc")
private String shortDesc;
#Column(name = "FullDescription")
#Lob
private String fullDescription;
#Column(name = "Image")
#Lob
private String image;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "category_model_category_id")
private CategoryModel categoryModel;
}
And even i have addnotation: "orphanRemoval = true" i still cant remove category when a product is assigned to it. Error looks like:
"#1451 - Cannot delete or update a parent row"
Can someone tell me how could i improve it?
I have three entity include bridge entity:
Team Entity:
public class Team {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "TEAM_ID")
private Integer id;
#Column(name = "teamname", length = 128, nullable = false, unique = true)
private String teamname;
#Column(name = "delete_date", length = 128, nullable = true)
private Date delete_date;
#Column(name = "description", nullable = true, length = 240)
private String description;
#Column(name = "active", length = 64, nullable = false)
private int active;
#OneToMany(mappedBy = "team", fetch = FetchType.LAZY)
private Set<TeamUsers> team_users = new HashSet<TeamUsers>();
---getter setter constructur
}
User Entity:
#Entity
#Table(name = "tblUsers")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name = "Username", length = 128, nullable = false, unique = true)
private String username;
#Column(name = "FirstName", nullable = false, length = 45)
private String firstName;
#Column(name = "LastName", nullable = false, length = 45)
private String lastName;
#Column(name = "Password", length = 64, nullable = false)
private String password;
#Column(name = "Email", length = 128, nullable = false, unique = true)
private String email;
#Column(name = "Phone", length = 64, nullable = false, unique = true)
private String phoneNumber;
#OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
private Set<TeamUsers> team_users = new HashSet<TeamUsers>();
---getter setter constructur
}
TeamUsers - Bridge Entity with extra column(active):
#Entity
#Table(name = "team_users")
public class TeamUsers implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#ManyToOne(fetch = FetchType.LAZY, optional = false, cascade = CascadeType.ALL)
#JoinColumn(name = "TEAM_ID")
private Team team;
#ManyToOne(fetch = FetchType.LAZY, optional = false, cascade = CascadeType.ALL)
#JoinColumn(name = "USER_ID")
private User user;
#Column(name = "active")
private Integer active;
---getter setter constructur
}
In the Team repository I have code:
package com.crmbackend.allService.teamService.repo;
import java.util.List;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.PagingAndSortingRepository;
import com.crmbackend.entity.Team;
public interface TeamRepository extends PagingAndSortingRepository<Team, Integer> {
#Query("select t from Team t")
public List<Team> getAllTeamAndDetails();
}
If I call the getAllTeamAndDetails() method in Junit Test, the result is all team informations:
It basically tells me how many team I have, and team users object who belong to which team.
Now, my question is which I want to get all team information and team user information,
but only their active = 1 in the bridge table.
which means if Team User record has active = 0, then this user should not showing in the result.
How this query should be looks like or what is the best approach?
Thanks
This is not possible with the plain JPA/Hibernate or Spring Data JPA tools available. You have to use a DTO for this purpose. I think this is a perfect use case for Blaze-Persistence Entity Views.
I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.
A DTO model for your use case could look like the following with Blaze-Persistence Entity-Views:
#EntityView(Team.class)
public interface TeamDto {
#IdMapping
Integer getId();
String getDescription();
#Mapping("team_users[active = 1].user")
Set<UserDto> getUsers();
#EntityView(User.class)
interface UserDto {
#IdMapping
Integer getId();
String getUsername();
}
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
TeamDto a = entityViewManager.find(entityManager, TeamDto.class, id);
The Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
Page<TeamDto> findAll(Pageable pageable);
The best part is, it will only fetch the state that is actually necessary!
using spring data and mysql as persistence layer getting some issues in Many to many mappings
#Getter
#Setter
public class BusinessUnitEntitiy extends AbstractTenantEntity implements Auditable{
private static final long serialVersionUID = -1123383144979037984L;
#Column(name = "NAME")
String name;
#Column(name = "DESCRIPTION")
String description;
#ManyToMany(fetch = FetchType.LAZY,mappedBy = "businessUnits" )
private Set<User> businessUsers;
public Set<User> fetchBusinessUsers() {
return businessUsers;
}
#Column(name = "DISPLAY_SEQUENCE_NUM")
protected Long displaySequenceNum;
#Column(name = "UNIQUE_SEQUENCE_ID",unique = true)
protected String uniqueSequenceId;
}
#Getter
#Setter
public class User extends AbstractTenantEntity {
private static final long serialVersionUID = 65981149772133526L;
#Column(name = "PROVIDER_USER_ID")
private String providerUserId;
private String email;
#Column(name = "enabled", columnDefinition = "BIT", length = 1)
private boolean enabled;
#Column(name = "DISPLAY_NAME")
private String displayName;
private String password;
private String provider;
#Column(name = "DISPLAY_SEQUENCE_NUM")
protected Long displaySequenceNum;
#Column(name = "UNIQUE_SEQUENCE_ID",unique = true)
protected String uniqueSequenceId;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(
name = "business_unit_user",
joinColumns={#JoinColumn(name ="user_id")},
inverseJoinColumns = { #JoinColumn(name="business_unit_id") }
)
Set<BusinessUnitJpaEntitiy> businessUnits;
}
fetching the user from businessunit works perfectly
but fetching businessunits from users gives null set even updating the same user is persisiting only the newly linked businessunit older values vanishes
If you persisted the user within the transaction without initializing the businessUnits fields, that's what you get. Either you also initialize the set correctly before persisting, or you detach the user after persisting, so that the user is reloaded from the database and the set is properly initialized.
you can try this
#ManyToMany
#JoinTable(
name = "business_unit_user",
joinColumns={#JoinColumn(name ="user_id",referencedColumnName = "id")},
inverseJoinColumns = { #JoinColumn(name="business_unit_id",referencedColumnName = "id") }
)
Set<BusinessUnitJpaEntitiy> businessUnits;
and you must have setter and getter for each property
I´m making the model classes using Hibernate, but I don´t know what to do with this kind of relationship.
I have three tables.
Adrress, employee and person.
One emplooye can have one adrress and one person can have one addrress.
I don´t know how map.
Because I thought to use embedded annotattion but doesn´t work.
First is to map my class, I need to put this two entities in address class?
What kind of annotattion i need to use?
I use a superclass with id property and every class extends.
I´m using mysql
my person class
#Entity
#Table(name = "destinatario")
public class Destinatario extends Persistent {
private static final long serialVersionUID = -7091318100871934315L;
#ManyToOne(cascade = CascadeType.PERSIST)
#JoinColumn(name = "endereco_id", referencedColumnName = "id")
private Endereco endereco;
#NotNull
#Size(max = 60)
#Column(name = "razao_social")
private String razaoSocial;
#NotNull
#Size(max = 14)
#Column(name = "inscricao_estadual")
private String inscricaoEstadual;
#Size(max = 9)
#Column(name = "inscricao_suframa")
private String inscricaoSuframa;
#Size(max = 60)
#Column(name = "email")
private String email;
#Size(max = 14)
#Column(name = "cnpj")
private String cnpj;
#Size(max = 11)
#Column(name = "cpf")
private String cpf;
#OneToMany
#JoinColumn(name = "destinatario_id")
private List<NotaFiscal> notaFiscais;
}
my address class
#Entity
#Table(name = "endereco")
public class Endereco extends Persistent {
private static final long serialVersionUID = -3308931308130690090L;
public enum UF {
AC("AC", "Acre"),
AL("AL", "Alagoas"),
AP("AP", "Amapá"),
AM("AM", "Amazonas"),
BA("BA", "Bahia"),
CE("CE", "Ceara"),
DF("DF", "Distrito Federal"),
ES("ES", "Espirito Santo"),
GO("GO", "Goiás"),
MA("MA", "Maranhão"),
MT("MT", "Mato Grosso"),
MS("MS", "Mato Grosso do Sul"),
MG("MG", "Minas Gerais"),
PA("PA", "Pará"),
PB("PB", "Paraíba"),
PR("PR", "Paraná"),
PE("PE", "Pernambuco"),
PI("PI", "Piauí"),
RJ("RJ", "Rio de Janeiro"),
RN("RN", "Rio Grande do Norte"),
RS("RS", "Rio Grande do Sul"),
RO("RO", "Rondônia"),
RR("RR", "Roraima"),
SC("SC", "Santa Catarina"),
SP("SP", "São Paulo"),
SE("SE", "Sergipe"),
TO("TO", "Tocantins");
private final String index;
private String descricao;
private UF(String index, String descricao) {
this.index = index;
this.descricao = descricao;
}
public String getNomeEstado() {
return descricao;
}
public String getIndex() {
return index;
}
}
#NotNull
#Size(max = 60)
#Column(name = "logradouro", unique = true)
private String logradouro;
#NotNull
#Size(max = 60)
#Column(name = "numero", unique = true)
private String numero;
#Size(max = 60)
#Column(name = "complemento")
private String complemento;
#NotNull
#Size(max = 60)
#Column(name = "bairro", unique = true)
private String bairro;
#NotNull
#Size(max = 60)
#Column(name = "municipio", unique = true)
private String municipio;
#Enumerated(EnumType.STRING)
#NotNull
//#Type(type = UFType.TYPE)
#Column(name = "uf", columnDefinition = "varchar", length = 2)
private UF uf;
#NotNull
#Size(max = 8)
#Column(name = "cep", unique = true)
private String cep;
#Size(max = 14)
#Column(name = "telefone")
private String telefone;
}
my methods to run and create a person by xml source
public static void main(String[] args) {
new Processadora().extrairDadosXml("diego");
ArquivoNotaFiscal arquivoNotaFiscal = null;
Destinatario destinatario = null;
NotaFiscal notaFiscal = null;
destinatario = createDestinatario();
arquivoNotaFiscal = createArquivoNotaFiscal();
notaFiscal = createNotaFiscal(arquivoNotaFiscal, emitente, destinatario);
destinatario.setNotaFiscais(Arrays.asList(notaFiscal));
DestinatarioDAO<Destinatario> destinatarioDAO = new DestinatarioDAOImpl<>();
Session session = HibernateSessionFactory.getSession();
Transaction transaction = session.getTransaction();
transaction.begin();
destinatarioDAO.save(destinatario);
transaction.commit();
}
private static Destinatario createDestinatario() {
Destinatario destinatario = new Destinatario();
Endereco endereco = new Endereco();
endereco.setLogradouro(nFeProc.getNfe().getInfNFe().getDestinatario().getEndereco().getLogradouro());
endereco.setNumero(nFeProc.getNfe().getInfNFe().getDestinatario().getEndereco().getNumero());
endereco.setBairro(nFeProc.getNfe().getInfNFe().getDestinatario().getEndereco().getBairro());
endereco.setComplemento(nFeProc.getNfe().getInfNFe().getDestinatario().getEndereco().getComplemento());
endereco.setCep(nFeProc.getNfe().getInfNFe().getDestinatario().getEndereco().getCep());
endereco.setMunicipio(nFeProc.getNfe().getInfNFe().getDestinatario().getEndereco().getMunicipio());
endereco.setUf(UF.valueOf(nFeProc.getNfe().getInfNFe().getDestinatario().getEndereco().getUF()));
endereco.setTelefone(nFeProc.getNfe().getInfNFe().getDestinatario().getEndereco().getTelefone());
destinatario.setEndereco(endereco);
destinatario.setRazaoSocial(nFeProc.getNfe().getInfNFe().getDestinatario().getRazaoSocial());
destinatario.setInscricaoEstadual(nFeProc.getNfe().getInfNFe().getDestinatario().getInscricaoEstadual());
destinatario.setInscricaoSuframa(nFeProc.getNfe().getInfNFe().getDestinatario().getInscricaoSuframa());
destinatario.setEmail(nFeProc.getNfe().getInfNFe().getDestinatario().getEmail());
destinatario.setCnpj(nFeProc.getNfe().getInfNFe().getDestinatario().getCnpj());
destinatario.setCpf(nFeProc.getNfe().getInfNFe().getDestinatario().getCpf());
return destinatario;
}
my database have foreign key constraint, I´m using mysql
I found my problem, I was saving only one object, because I thought if I use the save for the object who contains other it will save, but I need before save the address and later the person.
So this way everthing worked.