skip to Main Content

I have three classes in my Java project:

@Document(collection = "foos")
public class Foo {
 @Id
 private String id;
 private String foo_name;
 private Set<Bar> bars;
}

@Document(collection = "bazs")
public class Baz {
 @Id
 private String id;
 private String baz_name;
}

public class Bar {
 @DBRef
 private Baz baz;
 private String bar_name;
}

Then, I have /foo POST endpoint that accepts the body of a foo and stores it in a database.

@PostMapping
public Foo addFoo(@RequestBody Foo foo) {
    return repository.save(foo);
}

Given a Baz already stored in mongoDB with the id = ObjectId('62b795ea78aa537285762a1f') and name = the baz name, and I can call the /foo endpoint with the following body:

{ "foo_name" = "the foo name", "bars"= ["baz"= { "id" = "62b795ea78aa537285762a1f" }, "bar_name" = "the bar name"] }

I get a 200 OK, but the response looks like this:

{ "id" = "62b6e461cf1993ef423a28b3", "foo_name" = "the foo name", "bars"= ["baz"= { "id" = "62b795ea78aa537285762a1f", "baz_name" = null } , "bar_name" = "the bar name"]

If I use the GET endpoint /foo/62b6e461cf1993ef423a28b3, I do get all the @DBRef info:

{ "id" = "62b6e461cf1993ef423a28b3", "foo_name" = "the foo name", "bars"= ["baz"= { "id" = "62b795ea78aa537285762a1f", "baz_name" = "the baz name" } , "bar_name" = "the bar name"]

Note the difference in the baz_name variable.

How can I make my code return all the data once I save a new item foo? Or, at least, don’t send null values that are not real

2

Answers


  1. If you check source code of save method:

    public <S extends T> S save(S entity) {
    
            Assert.notNull(entity, "Entity must not be null.");
    
            if (entityInformation.isNew(entity)) {
                em.persist(entity);
                return entity;
            } else {
                return em.merge(entity);
            }
        }
    

    What it does is to check if this entity on which you called save is new one or existing. If entity is existing entity — which is the case for you, then it call merge rather than persist.

    Now, what actually happens in merge is it merge & returns the managed instance that the state was merged with. What it means is it either returns entity which exists PersistenceContext or creates a new instance all along.

    In any case, it will copy the state from the supplied entity, and return a managed copy. What it means in database terminology is it does upsert (INSERT or UPDATE) scenario.

    Meaning, it will insert if its new or update if its existing. Now in your case, since its already present entity, so it does update.

    In update case, the details which got updated are returned & other fields which didn’t get updated are not returned. Means in your case, except bar_name everything else got updated in database against id = ObjectId('62b795ea78aa537285762a1f') as that’s what you supplied in your input to save.

    Once update successful, it returned what got updated & not end result & that is reason you will see bar_name as null when you directly do

    return repository.save(foo); for existing record.

    If you really want to return full entity & not what got updated in database, you must do something like (provided your input will not necessarily containing all fields of entity) :

    @PostMapping
    public Foo addFoo(@RequestBody Foo foo) {
        repository.save(foo);
        return repository.findById(foo.getId()).get(); // here you can even throw exception as if entity didn't get saved as a part of save operation.
    }
    

    Further read : http://spitballer.blogspot.com/2010/04/jpa-persisting-vs-merging-entites.html

    Login or Signup to reply.
  2. The main question would be how you would describe the relationships between Bar and Foo.
    You seem to be treat it like a ManyToOne but the reference is store on Bar like a foreigh key in a relational database.
    Bar points to Foo implies the Foo is the owner and therefore you could annotated Foo having @DBRef Set bars.
    If the relationship is bidirectional you need to annotate both sides.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search