3
votes

Les valeurs nulles sont insérées dans les champs de clé étrangère avec Hibernate

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:

 entrez la description de l'image ici


8 commentaires

Les objets user et tag dans votre objet theQuestion 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 cela


Essayez d'utiliser Jackson Mapper


3 Réponses :


0
votes

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.


1 commentaires

Comment obtenir l'id de l'objet JSON et charger les objets dans le référentiel? Pouvez vous donner un exemple? Merci



0
votes

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;
    }   
}

  • Le nom de la colonne référencée par cette colonne de clé étrangère.
  • Lorsqu'il est utilisé avec des mappages de relations d'entité autres que les cas décrit ici, la colonne référencée est dans le tableau de la cible entité.
  • Lorsqu'il est utilisé avec un mappage de clé étrangère OneToMany unidirectionnel, le la colonne référencée est dans le tableau de l'entité source.
  • Lorsqu'elle est utilisée dans une annotation JoinTable, la colonne de clé référencée est dans la table d'entités de l'entité propriétaire, ou entité inverse si le join fait partie de la définition de jointure inverse.
  • Lorsqu'elle est utilisée dans un mappage CollectionTable, la colonne référencée est dans la table de l'entité contenant la collection.
  • Valeur par défaut (s'applique uniquement si une colonne de jointure unique est utilisée): le même nom comme colonne de clé primaire de la table référencée.

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"


0 commentaires

1
votes

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>


1 commentaires

Réveillé comme un charme! Je vous remercie