2010-07-21 13 views
5

tengo unas clases del modelo comoCómo obtener una lista correctamente mecanografiada de un ReflectionDBObject

public class MyClass extends ReflectionDBObject { 
    private List<NiceAttribute> attributes;  
    ... 
} 

public class NiceAttribute extends ReflectionDBObject { 
    ... 
} 

creo que de una manera typesafe, como

List<NiceAttribute> attrs = new ArrayList<NiceAttribute>(); 
attrs.add(new NiceAttribute()); 
MyClass myClass = new MyClass(); 
myClass.setAttributes(attrs); 

luego guardarlo en mongo, y recuperar con un código como

DBCollection col = ...; 
col.setObjectClass(MyClass.class) 
MyClass foundObject = (MyClass)col.findOne(); 

Pero el problema es que foundObject 's attributes se convierte en una lista de BasicDBObject. Parece que un controlador no puede (o no quiere) detectar un tipo de elemento de lista. ¿Es esto una limitación del conductor o me perdí algo? ¿Cuál sería una solución elegante para el problema?

Por cierto, sé de Morphia, etc. Quizás solucione el problema. Pero mi proyecto es pequeño, y no quiero complicar las cosas teniendo una capa más de abstracción.

Respuesta

-1

Deberías usar Morphia. Agrega soporte para POJO y objetos incrustados (y colecciones). No tiene ninguna de las limitaciones que tiene el controlador para requerir que sus clases se vean como Map<String, Object>.

+0

Morphia es de unos 10-15x más lento que el conductor. Es mejor escribir tu propio código para hacer el mapeo. –

+0

Tenemos pruebas de rendimiento en morphia que muestran que esto no es cierto. Si tiene algunas pruebas que muestran este problema de rendimiento, sería bueno si pudiera compartirlas. –

+0

De hecho, he hecho pruebas muy básicas, donde escribo la misma entrada unas 10-20 veces, usando el controlador, luego Spring Mongo Db y luego Morphia. El conductor es más rápido, Spring Mongo es aproximadamente 2 veces más lento y la morfina es aproximadamente 7-10 veces más lenta. Incluso en un mongo con fragmentación de colección real (en máquinas múltiples) es aún más lento. Puedes probar esto fácilmente –

4

Bueno, hay una solución, pero no te va a gustar. Básicamente puede especificar la clase correspondiente para una ruta interna dentro de su objeto. Esto es lo que hice, y funciona:

public class Release extends ReflectionDBObject { 

    //other fields omitted  

    private List<ReleaseDetailsByTerritory> releaseDetailsByTerritory = new ArrayList<ReleaseDetailsByTerritory>(); 

} 

public class ReleaseDetailsByTerritory extends ReflectionDBObject { //...} 

Ahora, si simplemente hacer esto:

releaseColl.setObjectClass(Release.class); 
    releaseColl.setInternalClass("ReleaseDetailsByTerritory.0", ReleaseDetailsByTerritory.class); 
    Release r = (Release) releaseColl.findOne(); 
    //the internal list will contain ReleaseDetailsByTerritory type objects (not DBObjects) 
    System.out.println(r.getReleaseDetailsByTerritory().get(0).getClass().getName()); 

Lo chungo es que no puedes o al menos no he encontrado (cómo) especificar la clase de mapeo para TODOS los elementos de una matriz incrustada. No se puede hacer algo como:

releaseColl.setInternalClass("ReleaseDetailsByTerritory", ReleaseDetailsByTerritory.class); 

o

releaseColl.setInternalClass("ReleaseDetailsByTerritory.*", ReleaseDetailsByTerritory.class); 

Tiene lugar para especificar la clase de mapeo de cualquier posible elemento de la matriz incrustada:

releaseColl.setInternalClass("ReleaseDetailsByTerritory.0", ReleaseDetailsByTerritory.class); 
releaseColl.setInternalClass("ReleaseDetailsByTerritory.1", ReleaseDetailsByTerritory.class); 
releaseColl.setInternalClass("ReleaseDetailsByTerritory.2", ReleaseDetailsByTerritory.class); 
Cuestiones relacionadas