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
user
ettag
dans votre objettheQuestion
existent-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 à null
pour celaEssayez d'utiliser Jackson Mapper