Recuerda que en las ciencias informáticas un error casi siempere suele tener diferentes resoluciones, de igual modo te compartiremos lo más óptimo y eficiente.
Solución:
“Conveniente” y “poderoso de usar” son objetivos contradictorios hasta cierto punto. Los repositorios son mucho más convenientes que las plantillas, pero estas últimas, por supuesto, le brindan un control más detallado sobre qué ejecutar.
Como el modelo de programación del repositorio está disponible para varios módulos de Spring Data, encontrará documentación más detallada en la sección general de los documentos de referencia de Spring Data MongoDB.
TL; DR
Generalmente recomendamos el siguiente enfoque:
- Comience con el resumen del repositorio y simplemente declare consultas simples utilizando el mecanismo de derivación de consultas o consultas definidas manualmente.
- Para consultas más complejas, agregue métodos implementados manualmente al repositorio (como se documenta aquí). Para el uso de implementación
MongoTemplate
.
Detalles
Para su ejemplo, esto se vería así:
-
Defina una interfaz para su código personalizado:
interface CustomUserRepository List
yourCustomMethod(); -
Agregue una implementación para esta clase y siga la convención de nomenclatura para asegurarse de que podamos encontrar la clase.
class UserRepositoryImpl implements CustomUserRepository private final MongoOperations operations; @Autowired public UserRepositoryImpl(MongoOperations operations) Assert.notNull(operations, "MongoOperations must not be null!"); this.operations = operations; public List
yourCustomMethod() // custom implementation here -
Ahora deje que su interfaz de repositorio base amplíe la personalizada y la infraestructura utilizará automáticamente su implementación personalizada:
interface UserRepository extends CrudRepository
, CustomUserRepository
De esta manera, básicamente tienes la opción: todo lo que es fácil de declarar entra en UserRepository
, todo lo que está mejor implementado manualmente entra en CustomUserRepository
. Las opciones de personalización se documentan aquí.
FWIW, con respecto a las actualizaciones en un entorno de subprocesos múltiples:
MongoTemplate
proporciona operaciones “atómicas” listas para usarupdateFirst
,updateMulti
,findAndModify
,upsert
… que te permiten modificar un documento en una sola operación. losUpdate
objeto utilizado por estos métodos también le permite orientar solo los campos relevantes.MongoRepository
solo te da el operaciones CRUD básicasfind
,insert
,save
,delete
, que funcionan con POJO que contienen todos los campos. Esto le obliga a actualizar los documentos en varios pasos (1.find
el documento a actualizar, 2. modificar los campos relevantes del POJO devuelto, y luego 3.save
it), o defina sus propias consultas de actualización a mano usando@Query
.
En un entorno de subprocesos múltiples, como por ejemplo, un back-end de Java con varios puntos finales REST, las actualizaciones de método único son el camino a seguir, para reducir las posibilidades de que dos actualizaciones simultáneas sobrescriban los cambios entre sí.
Ejemplo: dado un documento como este: _id: "ID1", field1: "a string", field2: 10.0
y dos subprocesos diferentes actualizándolo simultáneamente …
Con MongoTemplate
se vería algo así:
THREAD_001 THREAD_002
| |
|update(query("ID1"), Update().set("field1", "another string")) |update(query("ID1"), Update().inc("field2", 5))
| |
| |
y el estado final del documento es siempre _id: "ID1", field1: "another string", field2: 15.0
ya que cada hilo accede a la base de datos solo una vez y solo se cambia el campo especificado.
Considerando que el mismo escenario de caso con MongoRepository
se vería así:
THREAD_001 THREAD_002
| |
|pojo = findById("ID1") |pojo = findById("ID1")
|pojo.setField1("another string") /* field2 still 10.0 */ |pojo.setField2(pojo.getField2()+5) /* field1 still "a string" */
|save(pojo) |save(pojo)
| |
| |
y el documento final es _id: "ID1", field1: "another string", field2: 10.0
o _id: "ID1", field1: "a string", field2: 15.0
dependiendo de cual save
La operación llega al último DB.
(NOTA: Incluso si usamos Spring Data @Version
anotación como se sugiere en los comentarios, no cambiaría mucho: uno de los save
operaciones arrojarían un OptimisticLockingFailureException
, y el documento final seguirá siendo uno de los anteriores, con solo un campo actualizado en lugar de ambos).
Entonces yo diría eso MongoTemplate
es una mejor opcion, a menos que tenga un modelo POJO muy elaborado o necesite las capacidades de consultas personalizadas de MongoRepository
por alguna razón.
Esta respuesta puede demorarse un poco, pero recomendaría evitar toda la ruta del repositorio. Obtiene muy pocos métodos implementados de gran valor práctico. Para que funcione, se encuentra con la tontería de la configuración de Java en la que puede pasar días y semanas sin mucha ayuda en la documentación.
En su lugar, vaya con el MongoTemplate
enrute y cree su propia capa de acceso a datos que lo libere de las pesadillas de configuración que enfrentan los programadores de Spring. MongoTemplate
es realmente el salvador para los ingenieros que se sienten cómodos diseñando sus propias clases e interacciones, ya que hay mucha flexibilidad. La estructura puede ser algo como esto:
- Crear un
MongoClientFactory
clase que se ejecutará en el nivel de la aplicación y le dará unaMongoClient
objeto. Puede implementar esto como Singleton o usando un Enum Singleton (esto es seguro para subprocesos) - Cree una clase base de acceso a datos de la que pueda heredar un objeto de acceso a datos para cada objeto de dominio). La clase base puede implementar un método para crear un objeto MongoTemplate que los métodos específicos de su clase pueden usar para todos los accesos a la base de datos
- Cada clase de acceso a datos para cada objeto de dominio puede implementar los métodos básicos o puede implementarlos en la clase base
- Los métodos del controlador pueden llamar a métodos en las clases de acceso a datos según sea necesario.
Reseñas y valoraciones del artículo
Nos encantaría que puedieras mostrar este artículo si te valió la pena.