J'ai une entité Question Entity et Tag avec getter, méthodes setter et une relation OneToMany à partir de question à tag et une relation OneToOne de question à user
@Override
public void save(Question theQuestion) {
// get the current hibernate session
Session currentSession = entityManager.unwrap(Session.class);
// save employee
currentSession.saveOrUpdate(theQuestion);
}
Tag entity
{
"title": "stefanyyyxx",
"body": "stefandoyee44",
"date_created": "2019-02-27",
"user_id" : 1,
"tag_id": 1,
"answer_count": 0,
"view_count": 0
}
Lorsque j'essaie d'insérer une question à l'aide de Postman avec les détails suivants:
public class Tag {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@Column(name="name")
private String name;
@Column(name="username")
private String username;
@Temporal(TemporalType.DATE)
@Column(name="date_created")
private Date date_created;
public Tag() {
}
QuestionRepository.java:
public class Question {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@Column(name="title")
private String title;
@Column(name="body")
private String body;
@Temporal(TemporalType.DATE)
@Column(name="date_created")
private Date date_created;
@OneToOne(cascade=CascadeType.ALL)
@JoinColumn(name="user_id")
private User user;
@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="tag_id")
private Tag tag;
@Column(name="answer_count")
private int answer_count;
@Column(name="view_count")
private int view_count;
public Question() {
}
Des valeurs nulles sont insérées pour user_id et tag_id bien que j'aie utilisé JoinColumn () .
MySQL:
3 Réponses :
Vous avez une incompatibilité entre la structure JSON et @Entity . JSON contient des identificateurs numériques tandis que @Entity contient des objets réels représentant des relations. Vous devriez probablement introduire une classe DTO distincte pour mapper ce JSON tandis que dans @Repository vous devez charger les objets User et Tag en fonction de leur identifiant ou créez-en de nouveaux. Vous avez déjà CascadeType.ALL , donc Hibernate va cascade l'opération de persistance.
En général, la couche contrôleur doit être séparée de la couche référentiel à moins que vous ne fassiez quelque chose de très, très simple. Cela aide à faire évoluer le service sans changer le contrat API, par exemple. l'ajout de nouvelles colonnes pour l'audit des modifications. En exposant @Entity en tant que DTO, vous vous compliquez la vie sur la route.
Comment obtenir l'id de l'objet JSON et charger les objets dans le référentiel? Pouvez vous donner un exemple? Merci
Vous devez ajouter referencedColumnName dans la colonne de clé étrangère de votre entité enfant
@Entity
@Table(name="assetDetails")
public class AssetDetails {
@Id
@GeneratedValue
private BigInteger assetdetailid;
@JoinColumn(name = "assetid",nullable = false, updatable = false,referencedColumnName="assetid")
@OneToOne(cascade=CascadeType.ALL)
@JsonManagedReference
private Asset asset;
public Asset getAsset() {
return asset;
}
public void setAsset(Asset asset) {
this.asset = asset;
}
public AssetDetails(your fields,Asset asset) {
super();
//your fields
this.asset = asset;
}
}
Asset est l'entité parent et AssetDetails est l'entité enfant Ici, j'ai pris OneToOne Relationship
Asset.java
@Entity
@Table(name="asset")
public class Asset {
@Id
@GeneratedValue
@Column(name="assetid")
private BigInteger assetid;
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "asset")
@JsonBackReference
private AssetDetails assetDetails;
public AssetDetails getAssetDetails() {
return assetDetails;
}
public void setAssetDetails(AssetDetails assetDetails) {
this.assetDetails = assetDetails;
assetDetails.setAsset(this);
}
public Asset(your fields, AssetDetails assetDetails) {
super();
// your fields
this.assetDetails = assetDetails;
this.assetDetails.setAsset(this);
}
public Asset() {
super();
}
public BigInteger getAssetid() {
return assetid;
}
public void setAssetid(BigInteger assetid) {
this.assetid = assetid;
}
}
AssetDetails.java p>
referencedColumnName="your primaray key column name"
Comme le suggère @Karol Dowbecki,
convertissez le JSON en objet DTO et utilisez ce DTO pour obtenir les entités User , Tag de leurs référentiels respectifs .
Enfin, créez l'objet entité Question et stockez-le.
Entité Question
@Service
public class TestService {
@Autowired
private QuestionRepository questionRepository;
@Autowired
private UserRepository userRepository;
@Autowired
private TagRepository tagRepository;
public void addQuestion(QuestionDTO dto) {
Tag tag = null;
User user = null;
Question question = null;
Set<Tag> tags = null;
tag = tagRepository.findById(dto.getTag());
tags = new HashSet<>();
tags.add(tag);
user = userRepository.findById(dto.getUser());
question = new Question();
question.setTag(tags);
question.setUser(user);
question.setId(dto.getId());
question.setBody(dto.getBody());
question.setTitle(dto.getTitle());
question.setViewCount(dto.getViewCount());
question.setAnswerCount(dto.getAnswerCount());
question.setDateCreated(dto.getDateCreated());
questionRepository.save(question);
}
}
Entité utilisateur
public class QuestionDTO {
private Long id;
private String title;
private String body;
private Date dateCreated;
private Long user;
private Long tag;
private int answerCount;
private int viewCount;
}
Entité de balise
@Entity
@Table(name = "tag")
public class Tag {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@Column(name = "username")
private String username;
@Temporal(TemporalType.DATE)
@Column(name = "date_created")
private Date dateCreated;
}
Classe DTO
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
Classe de test
@Entity
@Table(name = "question")
public class Question {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "title")
private String title;
@Column(name = "body")
private String body;
@Temporal(TemporalType.DATE)
@Column(name = "date_created")
private Date dateCreated;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "user_id")
private User user;
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "tag_id")
private Set<Tag> tag;
@Column(name = "answer_count")
private int answerCount;
@Column(name = "view_count")
private int viewCount;
}
REMARQUE :
La relation entre Question et Tag est dans OneToMany vous devez utiliser le type Collection .
p>
Réveillé comme un charme! Je vous remercie
Les objets
userettagdans votre objettheQuestionexistent-ils? Sont-ils remplis?dans le schéma de base de données, ces champs sont-ils nullables ..? et avez-vous des enregistrements pour l'utilisateur et le tag avec l'ID 1?
@Nuthan Kumar les user_id et tag_id peuvent être nullables dans le schéma DB. J'ai des enregistrements pour l'utilisateur et le tag avec l'ID 1
@ayrton Dois-je définir les objets de balise utilisateur au lieu de simplement passer l'identifiant utilisateur et l'identifiant tag lors d'un appel REST car j'ai utilisé JoinColumn
pouvez-vous essayer avec @OneToOne (mappedBy = "user_id") utilisateur privé;
essayez "user": {"id": 1}, au lieu de "user_id": 1, et "tag": {"id": 1}, au lieu de "tag_id": 1,
@imperezivan a obtenu une exception
Un identifiant naturel immuable de l'entité com.springbootangular.discussionforum.entity.User a été modifié de bhar@mail.com à nullpour celaEssayez d'utiliser Jackson Mapper