Missing Foreign Keys when mapping Child Entities from JSON / How to generate them?

111 views Asked by At

I'm using JPA to to link a User to many Devices which can have many remote controls and these can contain many Commands (Buttons like ON / OFF / Change Channel / Volume etc.)

Thus far all my @OneToMany and @ManyToOne relations are working fine and making @GET call to my rest service gives me the Users and all of the devices and all the remotes etc. corresponding to that User, etc.

{
"devices": [{
    "deviceName": "Bedroom",
    "id": 2,
    "remotes": [{
        "commands": [{
            "commandName": "KEY_1",
            "id": 4
        },
        {
            "commandName": "KEY_3",
            "id": 7
        }],
        "id": 6,
        "remoteName": "Samsung TV Remote"
    },
    {
        "commands": [{
            "commandName": "KEY_4",
            "id": 8
        },
        {
            "commandName": "KEY_2",
            "id": 5
        }],
        "id": 3,
        "remoteName": "Samsung TV Remote 2"
    }]
}],
"id": 1,
"userName": "Cris"}

What I am trying to do is to create all of these at once when POSTing a JSON similair to this to my RESTful Webservice.(Mapping them straight to an Entity without manually parsing it)

{
"userName": "Cris",
"devices": [{
    "deviceName": "Bedroom",
    "remotes": [{
        "remoteName": "Samsung TV Remote",
        "commands": [{
            "commandName": "KEY_1"
        },
        {
            "commandName": "KEY_2"
        }]
    },
    {
        "remoteName": "Samsung TV Remote 2",
        "commands": [{
            "commandName": "KEY_3"
        },
        {
            "commandName": "KEY_4"
        }]
    }]
}]}

It creates them but all of the Child entities (Devices, Remotes, Commands) are not mapped to their parent, so their Foreign Keys are not being filled.

Here are my Entities:

Users

    private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

private String userName;

@OneToMany(mappedBy = "user", fetch=FetchType.LAZY,cascade=CascadeType.PERSIST)
private List<Devices> devices;

Devices

private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

private String deviceName;

@XmlTransient
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "USER_ID")
private Users user;

@OneToMany(mappedBy = "device",  fetch = FetchType.LAZY,cascade=CascadeType.PERSIST)
private List<Remotes> remotes;

Remotes

private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

private String remoteName;

@XmlTransient
@ManyToOne( fetch=FetchType.LAZY)
@JoinColumn(name = "DEVICE_ID")
private Devices device;

@OneToMany(mappedBy = "remote", fetch=FetchType.LAZY,cascade=CascadeType.PERSIST)
private List<Commands> commands;

Commands

private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

private String commandName;

@XmlTransient
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name = "REMOTE_ID")
private Remotes remote;

POST

@POST
@Override
@Consumes({"application/json"})
public void create(Users entity) {
    super.create(entity);
}

Is there a way of automatically mapping the child Entities to their parent after POSTing the JSON or will I need to manually map them to each other ?

Cheers

1

There are 1 answers

0
Cristopher Hornsey On

Ok so it took me a while but It's actually a very simple fix.

All I had to do was set the parent in the child entities when persisting the parent in the @POST method.

Here's an example for adding a device with a remote with commands. I added some try blocks incase any one of these entities didn't actually have a List of Child entities. It might not be the cleanest solution to preventing crashes caused by these certain Exceptions but it's working for what I need it to do.

@POST
@Consumes("application/json")
public void create(Devices device) {
     try {
        for (Remotes r : device.getRemotes()) {
            try {
                for (Commands c : r.getCommands()) {
                    c.setRemote(r);
                }
            } catch (Exception e) {
                System.out.println(r.getRemoteName() + ": commandList -> null");
            }
            r.setDevice(device);
        }
    } catch (Exception e) {
         System.out.println("remoteList -> null");
    }
    em.persist(device);
}