Morphia 0.9.9 (also tested against 1.00-SNAPSHOT)
http://groups.google.com/group/morphia/browse_thread/thread/7a91fce1ca54f78b
A project I'm working on stores a history of previous states of a
document. We have the main document (let's call it "MyDocument"),
which is an entity in its own right, and saved within a collection.
The way we're saving previous states is to store a copy of this
document within another document ("MyDocumentRevision") with a
timestamp of when the state was changed.
This works fine as far as persisting the data is concerned, however,
we run into an issue when retrieving the revisions. If we want to
retrieve all documents for a given revision, we correctly get back
multiple revisions. However, the "MyDocument" references within the
revision objects are all pointers to the same in-memory object. This
appears to occur because of how Morphia is determining whether to use
a cached version of a document. Specifically, it checks whether the
document has a populated ID field and that it has an @Entity
annotation:
Mapper.java:
Object fromDb(DBObject dbObject, Object entity, EntityCache cache) {
...
// check the history key (a key is the namespace + id)
if (dbObject.containsField(ID_KEY) &&
getMappedClass(entity).getIdField() != null
&& getMappedClass(entity).getEntityAnnotation() != null) {
Key key = new Key(entity.getClass(), dbObject.get(ID_KEY));
Object cachedInstance = cache.getEntity(key);
if (cachedInstance != null)
return cachedInstance;
else
cache.putEntity(key, entity); // to avoid stackOverflow in
recursive refs
}
...
}
Here is my test case that I used to confirm this behavior:
public class CreateTestDocuments{
public static void main(String[] args) throws Exception{
Datastore ds = getDatastore();
MyDocument doc1 = new MyDocument("Version 1");
ds.save(doc1);
MyDocumentRevision rev1 = new MyDocumentRevision(doc1);
ds.save(rev1);
doc1.setValue("Version 2");
ds.save(doc1);
MyDocumentRevision rev2 = new MyDocumentRevision(doc1);
ds.save(rev2);
}
private static Datastore getDatastore() throws UnknownHostException{
Mongo mongo = new Mongo();
Morphia morphia = new Morphia();
morphia.map(MyDocument.class).map(MyDocumentRevision.class);
Datastore datastore = morphia.createDatastore(mongo,
"morphia_test_database");
datastore.setDefaultWriteConcern(WriteConcern.SAFE);
return datastore;
}
}
public class RetrieveTestDocuments{
public static void main(String[] args) throws Exception{
Datastore ds = getDatastore();
Iterable<MyDocumentRevision> revisions =
ds.find(MyDocumentRevision.class).fetch();
Iterator<MyDocumentRevision> i = revisions.iterator();
MyDocumentRevision rev1 = i.next();
MyDocumentRevision rev2 = i.next();
if(rev1.getMyDocument() == rev2.getMyDocument()){
// This line throws an error
throw new AssertionFailure("The revisions should be different
objects");
}
}
private static Datastore getDatastore() throws UnknownHostException{
...
}
}
@Entity
public class MyDocument{
@Id
private ObjectId id;
public MyDocument(){}
public MyDocument(String value){this.value = value;}
// Getters and setters are below
...
}
@Entity
public class MyDocument{
@Id
private ObjectId id;
private String value;
public MyDocument(){}
public MyDocument(String value){this.value = value;}
// Getters and setters are below
...
}
package test;
import com.google.code.morphia.annotations.Embedded;
import com.google.code.morphia.annotations.Entity;
import com.google.code.morphia.annotations.Id;
import org.bson.types.ObjectId;
@Entity
public class MyDocumentRevision{
@Id
private ObjectId id;
@Embedded
private MyDocument myDocument;
public MyDocumentRevision(){}
public MyDocumentRevision(MyDocument doc){this.myDocument = doc;}
// Getters and setters are below
...
}
------
Is there a better way I should be achieving this, or is this truly a
bug in Morphia that should be addressed? I can confirm that the data
is being saved correctly in Morphia with different "value" values in
the MyDocument document.
Original issue reported on code.google.com by matthew.j.justin on 1 Jun 2011 at 6:20
Original issue reported on code.google.com by
matthew.j.justin
on 1 Jun 2011 at 6:20