-1

In the mysql database, the transaction table has successfully had the accountId field added via Java code. However, whenever I add a transaction on the React frontend, the account_id column value in the database is null. What could I be doing wrong?

Account entity:

@Entity
public class Account {
    
    @Id
    @GeneratedValue
    public long id;
    private String username;
    private String accountName;
    private Date asOfDate;
    
    @OneToMany(mappedBy="account", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    private List<Transaction> transactions = new ArrayList<>();

    protected Account() {
        
    }
    
    public Account(String username, String accountName, Date asOfDate) {
        super();
        this.username = username;
        this.accountName = accountName;
        this.asOfDate = asOfDate;
    }


    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }


    public void setUsername(String username) {
        this.username = username;
    }


    public String getAccountName() {
        return accountName;
    }


    public void setAccountName(String accountName) {
        this.accountName = accountName;
    }


    public Date getAsOfDate() {
        return asOfDate;
    }


    public void setAsOfDate(Date asOfDate) {
        this.asOfDate = asOfDate;
    }

    public List<Transaction> getTransactions() {
        return transactions;
    }

    public void setTransactions(List<Transaction> transactions) {
        this.transactions = transactions;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Account other = (Account) obj;
        if (id != other.id)
            return false;
        return true;
    }
}

Transaction entity:

@Entity
public class Transaction {
    
    @Id
    @GeneratedValue
    private long id;
    private String username;
    private Date transactionDate;
    private String transactionType;
    private String depositCategory;
    private String withdrawalCategory;
    private double transactionAmount;
    private String notes;
    
    @ManyToOne 
    @JoinColumn(name="account_id")
    private Account account;
    
    protected Transaction() {
        
    }
    
    public Transaction(String username, Date transactionDate, String transactionType, String depositCategory,
            String withdrawalCategory, double transactionAmount, String notes){
        super();
        this.username = username;
        this.transactionDate = transactionDate;
        this.transactionType = transactionType;
        this.depositCategory = depositCategory;
        this.withdrawalCategory = withdrawalCategory;
        this.transactionAmount = transactionAmount;
        this.notes = notes;
    }


    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }


    public void setUsername(String username) {
        this.username = username;
    }


    public Date getTransactionDate() {
        return transactionDate;
    }


    public void setTransactionDate(Date transactionDate) {
        this.transactionDate = transactionDate;
    }


    public String getTransactionType() {
        return transactionType;
    }


    public void setTransactionType(String transactionType) {
        this.transactionType = transactionType;
    }


    public String getDepositCategory() {
        return depositCategory;
    }


    public void setDepositCategory(String depositCategory) {
        this.depositCategory = depositCategory;
    }


    public String getWithdrawalCategory() {
        return withdrawalCategory;
    }


    public void setWithdrawalCategory(String withdrawalCategory) {
        this.withdrawalCategory = withdrawalCategory;
    }


    public double getTransactionAmount() {
        return transactionAmount;
    }


    public void setTransactionAmount(double transactionAmount) {
        this.transactionAmount = transactionAmount;
    }


    public String getNotes() {
        return notes;
    }


    public void setNotes(String notes) {
        this.notes = notes;
    }

    public Account getAccount() {
        return account;
    }

    public void setAccount(Account account) {
        this.account = account;
    }
    
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + (int) (id ^ (id >>> 32));
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Transaction other = (Transaction) obj;
        if (id != other.id)
            return false;
        return true;
    }
}

TransactionJpaResource:

@CrossOrigin(origins = "http://localhost:4200")
@RestController
public class TransactionJpaResource {

    @Autowired
    private TransactionService transactionService;
    
    @Autowired
    private TransactionJpaRepository transactionJpaRepository;

    @GetMapping("/jpa/users/{username}/transactions")
    public List<Transaction> getAllTransactions(@PathVariable String username) {
        return transactionJpaRepository.findByUsername(username);
    }
    
    @GetMapping("/jpa/users/{username}/transactions/{id}")
    public Transaction getTransaction(@PathVariable String username, @PathVariable long id) {
        return transactionJpaRepository.findById(id).get();
    }

    // DELETE /users/{username}/transactions/{id}
    @DeleteMapping("/jpa/users/{username}/transactions/{id}")
    public ResponseEntity<Void> deleteTransaction(@PathVariable String username, @PathVariable long id) {

        transactionJpaRepository.deleteById(id);

            return ResponseEntity.noContent().build();
    }
    
    //Edit/Update a Transaction
        //PUT /users/{username}/transactions/{id}
    @PutMapping("/jpa/users/{username}/transactions/{id}")
    public ResponseEntity<Transaction> updateTransaction(
            @PathVariable String username,
            @PathVariable long id, @RequestBody Transaction transaction){
        
        transaction.setUsername(username);
        
        Transaction transactionUpdated = transactionJpaRepository.save(transaction);
        
        return new ResponseEntity<Transaction>(transaction, HttpStatus.OK);
    }
            
    @PostMapping("/jpa/users/{username}/transactions")
    public ResponseEntity<Void> createTransaction (
            @PathVariable String username, @RequestBody Transaction transaction){
        
        transaction.setUsername(username);
        
        Transaction createdTransaction = transactionJpaRepository.save(transaction);
        URI uri = ServletUriComponentsBuilder.fromCurrentRequest()
                .path("/{id}").buildAndExpand(createdTransaction.getId()).toUri();
        
        return ResponseEntity.created(uri).build();
    }   
}

TransactionJpaRepository:

@Repository
public interface TransactionJpaRepository extends JpaRepository<Transaction, Long> {
    List<Transaction> findByUsername(String username);
}

Relevant React code from the transactions form:

let username = AuthenticationService.getLoggedInUsername();
    fetch(`http://localhost:8080/jpa/users/${username}/transactions`, {
      method: "POST",
      body: JSON.stringify({
        accountId: this.state.accountId,
        transactionDate: this.state.transactionDate,
        transactionType: this.state.transactionType,
        depositCategory: this.state.depositCategory,
        withdrawalCategory: this.state.withdrawalCategory,
        transactionAmount: this.state.transactionAmount,
        notes: this.state.notes,
      }),
      headers: {
        Accept: "application/json",
        "Content-Type": "application/json",
      },
    })
      .then((result) => result.text())
      .then((data) => console.log(data));
  };

...

handleAccountNameChange = (event) => {
    this.setState({ accountId: event.target.value });
  };
Cassiopeia
  • 37
  • 9
  • there is not much context. but you could add @JoinColumn(name="transaction_id", nullable=false) with @ManyToOne on Account account fields in transaction class. – sandip May 16 '21 at 21:35
  • You need to provide a JoinColumn on the ManyToOne @JoinColumn(name = "fk_account_id"). Without spring Jpa will create a extra table (junction table) for the Mapping which is unnecessary. – Daniel Rafael Wosch May 16 '21 at 21:38
  • You need to call `setAccount(account)` in your `Transaction`. [Related](https://stackoverflow.com/a/65766896/9860374) – Matheus May 16 '21 at 22:59

1 Answers1

1

This is what I did to fix the issue:

In React, in the transactions form:

fetch(`http://localhost:8080/jpa/users/${username}/transactions`, {
      method: "POST",
      body: JSON.stringify({
        username: this.state.username,
        transactionDate: this.state.transactionDate,
        transactionType: this.state.transactionType,
        depositCategory: this.state.depositCategory,
        withdrawalCategory: this.state.withdrawalCategory,
        transactionAmount: this.state.transactionAmount,
        notes: this.state.notes,
        account: ({
          id: this.state.accountId,
          username: this.state.username,
          accountName: this.state.accountName,
          asOfDate: this.state.asOfDate
        })
      }),

In the Account entity:

@Entity
@Table(name = "account")
public class Account {

    @Id
    @GeneratedValue
    public long id;
    private String username;
    private String accountName;
    private Date asOfDate;

    @OneToMany(mappedBy = "account", cascade = { CascadeType.PERSIST, CascadeType.ALL, CascadeType.MERGE })
    @JsonIgnore
    private List<Transaction> transactions = new ArrayList<>();

In the Transaction entity:

@Entity
@Table(name = "transaction")
public class Transaction {

In TransactionJpaResource:

@PostMapping("/jpa/users/{username}/transactions")
    public ResponseEntity<String> createTransaction(@PathVariable String username,
            @RequestBody Transaction transaction) {
        transaction.setUsername(username);      
        Transaction createdTransaction = transactionJpaRepository.save(transaction);
        URI uri = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}")
                .buildAndExpand(createdTransaction.getId()).toUri();
        ResponseEntity<Object> build = ResponseEntity.created(uri).build();
        int statusCodeValue = build.getStatusCodeValue();
        if (build.getStatusCodeValue() == 201) {
            return new ResponseEntity<String>("Data has been Inserted Successfully", HttpStatus.OK);
        } else {
            return new ResponseEntity<String>("Something went wrong", HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
Cassiopeia
  • 37
  • 9