Home > database >  Unable to save data correctly on Angular using Hibernate
Unable to save data correctly on Angular using Hibernate

Time:08-16

I am working on a small app where people can like posts they like, but I can't manage to do it. The backend sent a "Not-null property references a transient value" error which I tried to solve by adding "cascade = CascadeType.All" in the entities causing the issue, but when the data is saved, it also saves new items in child tables. To be more precise, I have this Thumbsup item to save, which has 3 columns (and all 3 are foreign keys) : fk_account, fk_merch and fk_post. When saving the Thumbsup, it creates a Merch item and then saves its id in fk_merch, which I do not want here.

Here is my thumbsup.java :

@NoArgsConstructor
@AllArgsConstructor
@Entity
public class Thumbsup {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int thumbsupId;

    @ManyToOne
    @JoinColumn(name = "fk_post", referencedColumnName = "postId")
    private Post post;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "fk_merch", nullable = true, referencedColumnName = "merchId")
    private Merch merch;

    @ManyToOne
    @JoinColumn(name = "fk_account", nullable = false, referencedColumnName = "accountId")
    private Account account;

    public static class Builder {
        int thumbsupId;
        Post post;
        Merch merch;
        Account account;

        public Builder setThumbsupId(int thumbsupId) {
            this.thumbsupId = thumbsupId;
            return this;
        }

        public Builder setPost(Post post) {
            this.post = post;
            return this;
        }

        public Builder setMerch(Merch merch) {
            this.merch = merch;
            return this;
        }

        public Builder setAccount(Account account) {
            this.account = account;
            return this;
        }

        public Thumbsup build() {
            return new Thumbsup(thumbsupId, post, merch, account);
        }
    }
}

merch.java :

@NoArgsConstructor
@AllArgsConstructor
@Entity
public class Merch {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int merchId;
    @NotNull
    private String itemname;
    @NotNull
    private double itemprice;
    private boolean active;
    private Date creation_date;
    private Date update_date;
    private Date deletion_date;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "fk_artist", nullable = false, referencedColumnName = "artistId")
    private Artist artist;

    public static class Builder {
        int merchId;
        String itemname;
        double itemprice;
        boolean active;
        Date creation_date = new Date();
        Date update_date;
        Date deletion_date;
        Artist artist;

        public Builder setMerchId(int merchId) {
            this.merchId = merchId;
            return this;
        }

        public Builder setItemname(String itemname) {
            this.itemname = itemname;
            return this;
        }

        public Builder setItemprice(double itemprice) {
            this.itemprice = itemprice;
            return this;
        }

        public Builder setActive(boolean active) {
            this.active = active;
            return this;
        }

        public Builder setCreation_date(Date creation_date) {
            this.creation_date = creation_date;
            return this;
        }

        public Builder setUpdate_date(Date update_date) {
            this.update_date = update_date;
            return this;
        }

        public Builder setDeletion_date(Date deletion_date) {
            this.deletion_date = deletion_date;
            return this;
        }

        public Builder setArtist(Artist artist) {
            this.artist = artist;
            return this;
        }

        public Merch build() {
            return new Merch(merchId, itemname, itemprice ,active, creation_date, update_date, deletion_date, artist);
        }
    }
}

post-structure.component.ts :

export class PostStructureComponent implements OnInit {
  @Input() post!: Post;
  credential!: Credential;
  accountDetail!: Account;
  artist!: Artist;
  selectedPost!: Post;
  thumbsup!: Thumbsup;
  thumbsups!: Thumbsup[];
  postForm!: FormGroup;

  constructor(public artistService: ArtistService,
              public postService: PostService,
              public thumbsupService: ThumbsupService,
              public accountService: AccountService,
              public auth: AuthService) {
  }

  ngOnInit(): void {
    this.auth.me().subscribe((response: ApiResponse) => {
      this.credential = CredentialHelper.credentialFromDto(response.data as CredentialDto);
      this.accountService.getDetail(this.credential.account.accountId.toString()).subscribe((account: Account) => {
        this.accountDetail = account;
        this.artistService.getDetail(this.accountDetail.accountId.toString()).subscribe((artist: Artist) => {
          this.artist = artist;
          this.thumbsupService.getListByPost(this.post.postId.toString()).subscribe((thumbsups: Thumbsup[]) => {
            this.thumbsups = thumbsups;
            this.thumbsups.forEach(thumbsup => {
              if (thumbsup.account.accountId == this.accountDetail.accountId){
                this.thumbsup = thumbsup;
              }
            })
          })
        })
      })
    })
  }

  onLike():void {
    let newThumbsup = {
       thumbsupId: 0,
       account: this.accountDetail,
       merch: MerchHelper.empty(),
       post: this.post
     }

    if (this.thumbsup == undefined ||this.thumbsup.thumbsupId == 0){
this.thumbsupService.create(ThumbsupHelper.returnCreatePayload(newThumbsup)).subscribe();
    } else {
      this.thumbsupService.deleteThumbsup(this.thumbsup.thumbsupId.toString()).subscribe();
    }
  }
}

thumbsup.helper.ts :

export class ThumbsupHelper {

  public static empty(): Thumbsup {
    return {
      thumbsupId: 0,
      account: AccountHelper.empty(),
      merch: MerchHelper.empty(),
      post: PostHelper.empty()
    }
  }
public static returnCreatePayload(thumbsup: Thumbsup): ThumbsupCreatePayload {
    return {
      account: thumbsup.account,
      merch: thumbsup.merch,
      post: thumbsup.post
    }
  }

I know that there are several and serious issues in my Angular code, such as getting credential, accountDetail and artist this way but I plan to modify this later, as well as . Also, I think that I should use Observables to manage data changes on thumbsup and evaluate if it exists or not to decide which method to call, but I have difficulties with it.

If anything is missing, I'll add it as soon as possible.

CodePudding user response:

If you want to refer to entities that already exist, you will have to load them via EntityManager.find(Class entityClass, Object id) or get a proxy reference to the object via EntityManager.getReference(Class entityClass, Object id).

So instead of using CascadeType.ALL in Thumbsup, you will have to set the fields of the associations merch, post and account with the object returned by find or getReference.

  • Related