I'm trying to create a reference to another model in Spring MognoDB.
I have a list of documents previously inserted into MongoDB using Mongoose so the references look like this:
{
...
address: ObjectId("5f596acb8ea1d54128016e97")
}
Following the Spring MongoDB documentation, I created two models:
#Document(collection = "person")
public class Person{
#Id
private String id;
... other attributes
#DBRef
private Address address;
}
Second model:
#Document(collection = "address")
public class Address{
#Id
private String id;
... other attributes
}
However this fails to return a document, showing the following error:
No converter found capable of converting from type [org.bson.types.ObjectId] to type [....models.Address]
Any idea how to solve this problem?
I also tried changing the id type to ObjectId but still getting the same error.
Related
The problem is that I am getting an exception using #RepositoryRestResource for my UserRepository that extends JpaRepository.
The reason for that is that findById is only accepting Long or Int types by default, even I have
#Id String id; and not #Id Int id in my entity definition.
I have tried searching StackOverflow and Google, but haven't found any solutions.
The error message is as follows:
"Failed to convert from type [java.lang.String] to type [java.lang.Integer] for value '3175433272470683'; nested exception is java.lang.NumberFormatException: For input string: \"3175433272470683\""
I want to make it work with a
#Id String id;
Any suggestions?
Many thanks in advances. It's a big privilege to ask questions here.
The Entity class:
#Entity // This tells Hibernate to make a table out of this class
#Table(name = "users")
public class XmppUser {
#Id
private java.lang.String username;
private String password;
private String serverkey;
private String salt;
private int iterationcount;
private Date created_at;
// #Formula("ST_ASTEXT(coordinates)")
// #Column(columnDefinition = "geometry")
// private Point coordinates;
// private Point coordinates;
private String full_name;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "username", nullable = true)
private XmppLast xmppLast;
You must change the type of the ID type parameter in the repository to match with the id attribute type on your entity.
From the Spring docs:
Interface Repository<T,ID>
Type Parameters:
T - the domain type the repository manages
ID - the type of the id of the entity the repository manages
Based on
#Entity // This tells Hibernate to make a table out of this class
#Table(name = "users")
public class XmppUser {
#Id
private java.lang.String username;
//...
}
It should be
public interface UserRepository extends CrudRepository<XmppUser, String> {
//..
}
See:
https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/CrudRepository.html#findById(ID)
https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/Repository.html
You could try something like this:
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
#Column(name = "PR_KEY")
private String prKey;
If you want to read more about this subject you could begin looking throw here or here
according to the latest version of spring data jpa(2.1.10 GA), you can use it like
here is the link
JpaRepository is a special case of CrudRepository. Both JpaRepository and CrudRepository declare two type parameters, T and ID. You will need to supply these two class types. For example,
public interface UserRepository extends CrudRepository<XmppUser, java.lang.String> {
//..
}
or
public interface UserRepository extends JpaRepository<XmppUser, java.lang.String> {
//..
}
Notice that the second type java.lang.String must match the type of the primary key attribute. In this case, you cannot specify it as String or Integer, but it is java.lang.String instead.
Try not to name a customized class as String. It is a bad practice to use the same class name as already present in the JDK.
I think there is an approach to solve this problem.
Let's say, Site is our #Entity.
#Id
private String id;
getters setters
then you can invoke findById as follow
Optional<Site> site = getSite(id);
Note: this worked for me, I hope it will help someone.
I'm trying to build a Spring Boot data layer on top of another project's DB. I'm want to get to a point where I can consume their data via Restful endpoints rather than directly from the DB. Maximum abstraction is the goal. Here's my problem. Consider the following JPA entity:
#Entity
#Table(name = "PERSON", schema = "public")
public class Person {
#Id private long id;
private String name;
private long favoriteFood;
private Address address;
//Getters, Setter etc.....
}
Notice that favoriteFood is a long, not a String. This is because the DB uses a lookup table. Let's say Joe's favorite food is pizza. The person table stores a 1 in the favorite_food column which is the fk to the "pizza" value stored in the food_ref table. This pattern is repeated hundreds or times in the DB. What is the best way to model this in JPA/Hibernate? Change the variable to String and have the getter and setter do the lookup? I've not found any examples which seems strange. This is a common DB structure. Any advice on best practices would be appreciated. Thanks!
The best way in this scenario is to use one to one relationship in the JPA entity with the FoodRef class
#Entity
#Table(name = "PERSON", schema = "public")
public class Person {
#Id private long id;
private String name;
#OneToOne(fetch=FetchType.LAZY)
#JoinColumn(name="food_ref_id")
private FoodRef favoriteFood;
private Address address;
//Getters, Setter etc.....
}
I'm trying to implement a Repository to work with Views. The fact is that I'm trying to use the SimpleJpaRepository implementation, but I'm getting a lot of errors on execution time because my DTO is not an #Entity. It is only a #Table, and it seems that this kind of elements are not mapped into the Metamodel of JPA.
This is my DTO:
#Table(name = "v_language")
public class VLanguage {
#Column(name = "isocode")
private String isocode;
#Column(name = "name")
private String name;
#Column(name = "isdefault")
private String isdefault;
// getters and setters
...
}
I tried to define a customized base repository with minimal functionality (only a findAll() method) with the same implementation of SimpleJpaRepository, but when building the Query it fails when doing:
Root<U> root = query.from(domainClass);
With this exception:
Caused by: java.lang.IllegalArgumentException: Not an entity: class es.prodevelop.pui.common.jpa.model.views.dto.VLanguage
at org.hibernate.jpa.internal.metamodel.MetamodelImpl.entity(MetamodelImpl.java:194)
at org.hibernate.jpa.criteria.QueryStructure.from(QueryStructure.java:124)
at org.hibernate.jpa.criteria.CriteriaQueryImpl.from(CriteriaQueryImpl.java:156)
at es.prodevelop.pui.common.jpa.configuration.AbstractRepository.applySpecificationToCriteria(AbstractRepository.java:213)
at es.prodevelop.pui.common.jpa.configuration.AbstractRepository.getQuery(AbstractRepository.java:174)
at es.prodevelop.pui.common.jpa.configuration.AbstractRepository.findAll(AbstractRepository.java:151)
...
Does anybody know how to solve it?
you are missing the #Entity annotation.
please annotate your class and try again.
I am getting an error when using an Oracle DB and Spring Data. The error is:
ORA-00942: table or view does not exist
The cause of this error is that the user I am connecting with does not have access to the tables in the schemas I wish to connect to.
I read that 2 fixes to this are to create synonyms in my database or to specify the schema that each entity/table belongs to.
I am going to try the Schema approach first. How do I do so?
My example entity below, a Dog in the Vet Schema:
#Entity
#Table(name = "Dog")
public class Dog
{
#Id
private String id;
#Column(name = "NAME")
private String name;
#Column(name = "Owner")
private String owner;
//getters and setters etc...
The #Table annotation provides the schema attribute:
#Table(name = "Dog", schema = "Vet")
You must prefix your tables with the schema name and with a . inbetween them:
#Table(name = "VET.Dog")
I have the following object structure:
#Document(collection = "user")
#TypeAlias("user")
public class User {
#Id
private ObjectId id;
private Contact info = new Contact();
}
and here is the Contact pojo:
public class Contact {
#Indexed(unique = true)
private String mail;
}
But for some reasons not known to me, I don't see Spring-data creating a unique index for the property info.mail
To summarize, I have this json structure of user object:
{_id:xxxxx,info:{mail:"abc#xyz.shoes"}}
And I want to create a unique index on info.mail using Spring data with the above pojo structure. Please help.
As far as I remember, annotating embedded fields with #Indexed will not work. #CompoundIndex is the way to go:
#Document(collection = "user")
#TypeAlias("user")
#CompoundIndexes({
#CompoundIndex(name = "contact_email", def = "{ 'contact.mail': 1 }", unique = true)
})
public class User {
#Id
private ObjectId id;
private Contact info = new Contact();
}
In my case I had a fresh spring boot application 2.3.0 with just #Document, #Id and #Indexed annotations. I was able to retrieve and insert documents but it refused to create the index other than the PK. Finally I figured that there is a property that you need to enable.
spring.data.mongodb.auto-index-creation = true
As a matter of fact it even works on nested objects without #Document annotation.
Hope this helps :)
Obsolete answer, this was with and older version of mongodb 1.x.
Had the same issue, it seems that your Contact class is missing the #Document annotation i.e.
#Document
public class Contact {
#Indexed(unique = true)
private String mail;
}
Should work, quote from the spring mongodb reference
Automatic index creation is only done for types annotated with #Document.
Extending #Xenobius's answer:
If any configuration extending AbstractMongoClientConfiguration is set, MongoMappingContext will back off. The result is:
spring.data.mongodb.auto-index-creation = true will not be effective
You will need add this into your own configuration:
#Override
protected boolean autoIndexCreation() {
return true;
}
ref: https://github.com/spring-projects/spring-boot/issues/28478#issuecomment-954627106