My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for

EntityAnnotation  
Define your Entity
Updated Aug 14, 2010 by sport11...@gmail.com

Entity Annotation

If you want to store your class instance in Mongo via Morphia, the first thing you need to do is annotate your class as an @Entity:

import com.google.code.morphia.annotations.Entity;

@Entity
public class Hotel {
...
}

Name + Constructor

You can also optionally set a name for your MongoDB DBCollection name. You will also need a (no-args) default constructor.

@Entity("hotels")
public class Hotel {
...
    public Hotel() {
    }
...
}

Note that your default constructor does not need to be public, it can also be protected or private.

Class name in document and how to suppress it

The @Entity annotation provides another optional parameter to not store the class name in the document.

@Entity(value="hotels", noClassnameStored=true)
public class Hotel {
...
    public Hotel() {
    }
...
}

The default behavior is to store the class name in the document.

Why would you need it? This is mainly used when storing different entities in the same collection and reading them back as the base or super class.

Ex.

@Entity("animals") abstract class Animal { String name; } 
@Entity("animals") Cat extends Animal { ... } 
@Entity("animals") Dog extends Animal { ... } 

//And then performing the following query...
List<Animal> animals = ds.createQuery(Animal.class).asList(); 

As you can see, without the class name stored in the document, Morphia wouldn't know which class to actually create.

If you are only storing a single entity type in the collection and you are concerned about datasize, it would be safe to add the noClassnameStored=true parameter to the Entity annotation.

@Id

Classes annotated with @Entity require unique @Id values; these values are stored in the MongoDB "id" field, which has a unique index requirement. The Hotel class above would have:

@Entity
public class Hotel {

    @Id
    private ObjectId id;
...
}

Mongo will generate the Id for your new objects, so you don't need to worry about that. It will be stored as an ObjectId; If you use any other type than ObjectId you must set the value yourself.

@Indexed

This annotation applies an index to a field. The indexes are applied when the datastore.ensureIndexes() method is called... more on this below.

You apply the Indexed annotation on the field you want indexed by MongoDB.

@Entity
public class Product {

    @Id
    private ObjectId id;

    @Indexed(value=IndexDirection.ASC, name="upc", unique=true, dropDups=true) 
    private String upcSymbol;
...
}

The parameters are:

value: Indicates the direction of the index; IndexDirection.ASC (ascending), IndexDirection.DESC (descending), IndexDirection.BOTH (both), default is ascending

name: The name of the index to create; default is to let the mongodb create a name (in the form of key1_1/-1_key2_1/-1...

unique: Creates the index as a unique value index; inserting duplicates values in this field will cause errors, default false

dropDups: Tells the unique index to drop duplicates silently when creating; only the first will be kept. default false

Datastore.ensureIndexes() needs to be called to apply the indexes to MongoDB. The method should be called after you have registered your entities with Morphia. It will then synchronously create your indexes. This should probably be done each time you start your application.

Note: Doing this on an existing system, with existing indexes and capped collections, should take no time (and do nothing).

Morphia m = ...
Datastore ds = ...

m.map(Product.class);
ds.ensureIndexes(); //creates all defined with @Indexed

You can read more about MongoDB indexes here, http://www.mongodb.org/display/DOCS/Indexes

Embedded

You can also choose to create a class that will be embedded in the Entity, we use the @Embedded annotation in this case. For example, the Hotel class above might have an Address. The Address would be an inseparable part of the Hotel, would not have its own ID, and would not be stored in a separate collection. In this case we would annotate the Address class as @Embedded:

@Entity
public class Hotel {
    ...
    @Id
    private ObjectId id;

    @Embedded
    private Address address;
    ...
}

...

@Embedded
public class Address {
    ...
}

As you can see, classes with @Embedded annotation do not need an @Id. This is because they always be included in another class. In fact, they are not allowed to have an @Id if the class is annotated with @Embedded.

Comment by amaury.m...@gmail.com, Aug 20, 2010

Hi team, it could be usefull to get a way to ignore an inherited field via annotation.

ie : one domain extends Observable, "change" and "obs" inherited fields could be marked "transient"

Comment by project member scotthernandez, Aug 20, 2010

Amaury, some people might find that useful. Currently there is no support for that but it is relatively easy to add as an extension in your own code.

If you need more help or just want to ask for the feature, please file an issue (http://code.google.com/p/morphia/issues/list).

Comment by kevin.lu...@gmail.com, Sep 21, 2011

Hi, I have a collection that is stored by a different team, does not follow the class per collection rule, and does not have className in the document (instead it has a type enum which is sort of like a class name but won't work with morphia). It seems like morphia should be able to easily support an optional interface something like this:

interface ConversionPolicy? {
// give back to morphia the class name that should be applied to this DBObject Class classFrom(DBObject obj);
}

The default implementation could be to lookup the className value in the DBObject and return a class for that, which means clients that have control over both sides don't do anything and don't have to know anything about a ConversionPolicy?. But peeps like me who are unfortunate can implement a custom ConversionPolicy? and still use morphia.

What do you think?

Comment by dmitry.g...@gmail.com, Oct 26, 2011

Morphia can save and load classes without default constructor. The trick is very simple

morphia.getMapper().getOptions().objectFactory=new DefaultCreator() {
@Override
public Object createInstance(Class clazz,
                             com.mongodb.DBObject dbObj) {
if(clazz.equals(ThirdPartyClass.class)) {
return new ThirdPartyClass(dbObj.get("something_required"));
}
return super.createInstance(clazz,dbObj);
}
};
Comment by breevan...@gmail.com, Jan 12, 2012

Is it possible to disable class name storage on embedded documents? If so, how?

Comment by hendy.soluvas@gmail.com, Apr 13, 2012

Thank you Dmitry !! :)

Comment by hendy.soluvas@gmail.com, Apr 13, 2012

I support Kevin's idea!


Sign in to add a comment
Powered by Google Project Hosting