0

One Group has many Users:

Group

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonManagedReference;

import javax.persistence.*;
import java.util.Collection;
import java.util.List;

@Entity
@Table(name = "GROUPS")
public class Group {

    @Id
    @Column(name = "ID")
    private Long ID;

    @Column(name = "NAME")
    private String NAME;

    //@JsonManagedReference
    @OneToMany(mappedBy = "group"
            //, fetch = FetchType.EAGER
            //, cascade = CascadeType.ALL
    )
    private List<Users> itsUser;

    //getters and setters are omitted for clarity
}

Users

import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import com.fasterxml.jackson.annotation.JsonProperty;

import javax.persistence.*;
import static javax.persistence.GenerationType.SEQUENCE;

@Entity
@Table(name = "USERS")
@SequenceGenerator(name = "SEQUENCE_USER_ID",     //my own name in java (unique)
        sequenceName = "GENERATOR_SEQUENCE_USERS",     //in database
        initialValue = 1,
        allocationSize = 1)
public class Users {

    @JsonProperty(value = "id") //these play a role when both reading or writing
    @Id
    @Column(name = "ID")
    @GeneratedValue(strategy=SEQUENCE, generator="SEQUENCE_USER_ID")
    private Long ID;

    @JsonProperty(value = "name")
    @Column(name="NAME")
    private String NAME;

    @JsonProperty(value = "username")
    @Column(name="USERNAME")
    private String USERNAME;

    @JsonProperty(value = "password")
    @Column(name="PASSWORD")
    private String PASSWORD;

    @JsonProperty(value = "email")
    @Column(name="EMAIL")
    private String EMAIL;

    @JsonProperty(value = "picture")    //Now it works with both mypic and picture as json keys
    @Column(name="PICTURE")
    private String PICTURE;

    //@Column(name="GROUP_ID")  //we already have a ManyToOne for this, we cannot repeat it
    @JsonProperty(value = "groups_id")
      //to ignore it in jpa (http://stackoverflow.com/questions/1281952/jpa-fastest-way-to-ignore-a-field-during-persistence)
    private Long itsGroupId;

    @Transient
    public Long getItsGroupId() {
        if(itsGroupId == null) {
            this.itsGroupId = group.getID();
        } else {
            //nop
        }
        return itsGroupId;
    }

    public void setItsGroupId(Long itsGroupId) {
        this.itsGroupId = itsGroupId;
    }

    //@JsonIgnore
    //@JsonProperty(value = "groups_id")
    //@JsonBackReference
    @ManyToOne(optional = false, targetEntity = Group.class)
    @JoinColumn(
            name = "GROUP_ID",  //column name
            referencedColumnName = "ID"   //reference name
    )
    private Group group;

   //getters and setters are omitted for clarity
}

We are using Spring with Spring-data and Jackson to do things automagically but we cannot configure the magic:

We are trying to stick on the following constraints at the same time:

1) Keep the ability to have a reference to the groupId and the ManyToOne relationship group.
This is easy to be achieved by putting @Transient annotation at the groupId because @Column is not allowed since we have already declared the @ManyToOne annotation. You also have to implement the getGroupId method accordingly.

2) Return a json of Users class that contains the groups_id.
This can be implemented by setting the @JsonProperty annotation.

3) Create a user class, and also save it in the database, by a json. The json contains groups_id which has as a value an integer for the foreign key.
This does not work because by setting it @Transient above, then the system refuses to save in the database something that is transient or at least this is how we interpret this exception:

HTTP Status 500 - Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: not-null property references a null or transient value: com.pligor.mvctest.models.Users.group; nested exception is org.hibernate.PropertyValueException: not-null property references a null or transient value: com.pligor.mvctest.models.Users.group

George Pligoropoulos
  • 2,919
  • 3
  • 33
  • 65

1 Answers1

1

On the backend do something like this:

Group group = groupRepository.findById(userResource.getGroupId());
if (group != null) {
   User user = new User(userResource);
   user.setGroup(group);
   userRepository.save();
}

The idea behind this is that you need to fetch the group from the DB, to be able to link it with the newly created User

WeMakeSoftware
  • 9,039
  • 5
  • 34
  • 52
  • we thought that the original configuration was the issue, but we guess there is no other alternative. thank you – George Pligoropoulos Oct 22 '15 at 13:00
  • Actually you can make it ever simpler than that avoiding a call to the db by creating a Group instance that has only set its ID and all the other fields are null. If you `user.setGroup(group)` and then save it still works but thanks for the answer – George Pligoropoulos Oct 22 '15 at 13:02
  • we are leaving answering open for a little bit more to allow others provide more elegant solutions if there are any. – George Pligoropoulos Oct 22 '15 at 13:02
  • 1
    if you create a new group with only ID field defined you may accidentally delete information about the group (if you save it explicitly, or if your flushMode is set to AUTO) – WeMakeSoftware Oct 22 '15 at 13:04