Search code examples
mongodbhibernatehibernate-ogm

Missing collections in entities using Hibernate OGM with mongodb


The collections in my entities don't get persisted, whether it's a simple collection or association.
I'm using OGM with mongodb.

For an example of the problem consider the following entities:

@Entity
class Document {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Type(type = "objectid")
    String id;

    String name;

    @ElementCollection
    Set<String> names;

    Document() {
        this.names = new HashSet<>();
    }

    Document(String name) {
        this();
        this.name = name;
    }
}

@Entity
class ChildDocument {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Type(type = "objectid")
    String id;

    String name;

    ChildDocument() {}

    ChildDocument(String name) {
        this.name = name;
    }
}

class ParentDocument {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Type(type = "objectid")
    String id;

    int count;

    @OneToMany(cascade = CascadeType.ALL)
    @AssociationStorage(AssociationStorageType.IN_ENTITY)
    List<ChildDocument> kids = new LinkedList<>();
}

The following setup:

final StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder()
        .applySetting(OgmProperties.ENABLED, true)
        .applySetting(AvailableSettings.TRANSACTION_COORDINATOR_STRATEGY, "jta")
        .applySetting(AvailableSettings.JTA_PLATFORM, "JBossTS")
        .applySetting(OgmProperties.DATASTORE_PROVIDER, MongoDB.DATASTORE_PROVIDER_NAME)
        .applySetting(OgmProperties.DATABASE, "testdb")
        .applySetting(OgmProperties.CREATE_DATABASE, "true");

final StandardServiceRegistry registry = registryBuilder.build();
final MetadataSources sources = new MetadataSources(registry);
sources.addAnnotatedClass(Document.class);
sources.addAnnotatedClass(ChildDocument.class);
sources.addAnnotatedClass(ParentDocument.class);

final SessionFactory sessionFactory = sources.buildMetadata().getSessionFactoryBuilder()
        .unwrap(OgmSessionFactoryBuilder.class)
        .build();

And this short program:

Document document1 = new Document("one");
Document document2 = new Document("two");
document2.names.add("one.one");
document2.names.add("one.two");

ParentDocument parent = new ParentDocument();
parent.count = 2;
parent.kids.add(new ChildDocument("one"));
parent.kids.add(new ChildDocument("two"));

final Session session = sessionFactory.openSession();
session.save(document1);
session.save(document2);
session.save(parent);
session.close();

sessionFactory.close();

The testdb now contains 3 collections: Document, ChildDocument and ParentDocument.

  • The ChildDocument documents are correct as they only need to have the _id and name
  • The Document documents also contain only the _id and name, the names collection is missing
  • In ParentDocument only the _id and count are persisted but the reference to the kids is missing even though the ChildDocuments are created

What am I doing wrong?
Thanks


Solution

  • Hibernate OGM under the hood execute some optimizations and therefore commands are not execute immediately on the db (usually).

    When using Hibernate OGM you should still use transaction demarcation for your operations:

       final Session session = sessionFactory.openSession();
    
       session.beginTransaction();
    
       session.save(document1);
       session.save(document2);
       session.save(parent);
    
       session.getTransaction().commit();
    
       session.close();
    

    This is explained in the documentation: http://docs.jboss.org/hibernate/ogm/5.0/reference/en-US/html/ch11.html#transactions

    Note that using session.flush() before session.close() would work as well in this case.