Is there any chance to make the #Id property non-nullable for Mongo-related entities in Kotlin?
Referring to this post there seems to be a solution for SQL by setting the ID initially to 0. However, that seems like a hack, and seems to work only when using sequence generators.
My original intent is obviously to avoid nullable IDs like I have right now:
#Document class MyEntity( #Id var id: String? = null )
What I'd prefer if possible:
#Document class MyEntity( #Id val id: String )
You can use lateinit, but this may lead to a runtime error:
#Document
class File : Serializable {
#Id
lateinit var id: ObjectId
}
#Document(collection = COLLECTION_MY_ENTITY)
data class MyEntity #PersistenceConstructor constructor (
#Id val id: String,
#Field(FIELD_NAME) someField: String
)
Related
I need to auto generate the id on my documents for persist on database. But if i don't set the id it has an error that cannot be null. How could I generate the id for reduce the repeated code and make it simple?
#Id
private ObjectId id;I found a solution that is,
must the type of the id be an org.bson.types.ObjectId, like above:
#ToString
#Getter
#NoArgsConstructor
#RequiredArgsConstructor(staticName = "of")
public class Guide {
#Id
private ObjectId id;
#NonNull
private String name;
}
The right place that are the solution is:
#Id private ObjectId id;
I'm using org.springframework.cloud:spring-cloud-gcp-starter-data-datastore with Kotlin.
The code look like this:
#Entity(name = "books")
data class Book(
#Reference val writer: Writer,
var name: String,
#Id val id: Key? = null, //I leave the key as NULL so it that can be autogenerated
)
#Entity(name = "writers")
data class Writer(
var name: String,
#Id val id: Key? = null
)
//Also with Repositories
When I save a Book entity, with a reference to a saved Writer, when I retrieve it, it should be retrieved automatically right?
Sample code:
var w = Writer("Shakespeare")
w = writerRepo.save(w)
var book = Book(w, "Macbeth")
book = bookRepo.save(book)
books = bookRepo.findByWriter(w) //Error happen here
The code above will throw error failed to instantiate Book with NULL Writer. Any idea why this happen?
I find the answer is not because the relationship is not persisted but because The Repository set the relationship Entity after instantiation. The Repository tries to instantiate the Entity first, assign NULL on relationship (annotated with #References) attribute.
Therefore, the Entity should be like this:
#Entity(name = "books")
data class Book(
#Reference var writer: Writer?, //Accepting NULL values
var name: String,
#Id val id: Key? = null
)
And all works well.
FullTextQuery.setProjection("id", "author") ignored author's id, name property. How can I retrieve these properties?
#MappedSuperclass
class BaseContent{
#IndexedEmbedded(prefix = "author.", includePaths = {"id", "name"}) #ManyToOne
Author author;
}
#Entity #Indexed
class Content extends BaseContent{
#Id #DocumentId
Integer id;
}
#Entity
class Author{
#Id
Integer id;
#Field(store = Store.YES)
String name;
}
EDIT:
Is this query correct?.
FullTextQuery ftq = fullTextSession.createFullTextQuery(luceneQuery, Content.class);
ftq.setProjection("id", "author.id", "author.name");
ftq.setResultTransformer(new AliasToBeanResultTransformer(Content.class));
List<Content> result = ftq.list();
Use the author. prefix.
fullTextQuery.setProjection("author.id", "author.name")
EDIT: Did you try inspecting the results without your transformer? It should return a List<Object[]> with the content of the projections. If it does, then it's the transformer that isn't working. I very much doubt that AliasToBeanResultTransformer is able to handle composite aliases such as "author.name". You'll probably need you own transformer.
Also note that:
If you just want to get the Content entity, and getting it from the database doesn't bother you, just remove the projection and result transformer: Hibernate Search will get a List<Content> from the database for you.
If what you're trying to do is to avoid loading anything from the database, then you're on the right path. But as I said, you'll probably need a custom transformer.
I have a Gfh_i18n entity, with a composite key (#IdClass):
#Entity #IdClass(es.caib.gesma.petcom.data.entity.id.Gfh_i18n_id.class)
public class Gfh_i18n implements Serializable {
#Id #Column(length=10, nullable = false)
private String localeId = null;
#Id <-- This is the attribute causing issues
private Gfh gfh = null;
....
}
And the id class
public class Gfh_i18n_id implements Serializable {
private String localeId = null;
private Gfh gfh = null;
...
}
As this is written, this works. The issue is that I also have a Gfh class which will have a #OneToMany relationship to Gfh_i18n:
#OneToMany(mappedBy="gfh")
#MapKey(name="localeId")
private Map<String, Gfh_i18n> descriptions = null;
Using Eclipse Dali, this gives me the following error:
In attribute 'descriptions', the "mapped by" attribute 'gfh' has an invalid mapping type for this relationship.
If I just try to do, in Gfh_1i8n
#Id #ManyToOne
private Gfh gfh = null;
it solves the previous error but gives one in Gfh_i18n, stating that
The attribute matching the ID class attribute gfh does not have the correct type es.caib.gesma.petcom.data.entity.Gfh
This question is similar to mine, but I do not fully understand why I should be using #EmbeddedId (or if there is some way to use #IdClass with #ManyToOne).
I am using JPA 2.0 over Hibernate (JBoss 6.1)
Any ideas? Thanks in advance.
You are dealing with a "derived identity" (described in the JPA 2.0 spec, section 2.4.1).
You need to change your ID class so the field corresponding to the "parent" entity field in the "child" entity (in your case gfh) has a type that corresponds to either the "parent" entity's single #Id field (e.g. String) or, if the "parent" entity uses an IdClass, the IdClass (e.g. Gfh_id).
In Gfh_1i8n, you should declare gfh like this:
#Id #ManyToOne
private Gfh gfh = null;
Assuming GFH has a single #Id field of type String, your ID class should look like this:
public class Gfh_i18n_id implements Serializable {
private String localeId = null;
private String gfh = null;
...
}
In many sources I have read PrimaryKey Classes and even JPA2 entities should be serializable.
IN my example (legacy database) there is a relationship between employee and languages:
Employee Class:
#Entity
#IdClass(EmpleadoId.class)
#Table(name = "NO_INFGRAEMPL")
public class Empleado {
#Id
#Column(name = "IGECOMPANIA", unique = true)
private String compania;
#Id
#Column(name = "IGENUMEROIDENTIFIC", unique = true)
private String numeroIdentificacion;
//...
}
Employee Compound PrimaryKey Class:
public class EmpleadoId {
private String compania;
private String numeroIdentificacion;
//...
}
Employee Language SKill Class:
#Entity
#IdClass(IdiomaEmpleadoId.class)
#Table(name = "NO_IDIOMEMPLE")
public class IdiomaEmpleado {
#Id
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumns(value = {
#JoinColumn(name= "IEMCOMPANIA", referencedColumnName = "IGECOMPANIA"),
#JoinColumn(name = "IEMEMPLEADO", referencedColumnName = "IGENUMEROIDENTIFIC")
})
private Empleado empleado;
#Id
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "IEMIDIOMA")
private Idioma idioma;
#Column(name = "IEMNIVELLECTURA")
private String nivelLectura;
//...
}
Employee Language Skill Compound PrimaryKey Class:
public class IdiomaEmpleadoId {
private EmpleadoId empleado;
private String idioma;
//...
}
Language Class:
#Entity
#Table(name = "NO_IDIOMAS")
public class Idioma {
#Id
#Column(name = "IDICODIGO")
private String codigo;
#Column(name = "IDIDESCRIPCION")
private String descripcion;
//...
}
I am using EclipseLink JPA2 Provider under a J2SE application and it is not giving me any exceptions.
My questions are:
Why is it not giving me exceptions? Is it not enforced to have Serializable?
Is it safe to continue this way or should I definitely implemente serializable?.
In which ones?, JPA2 Entities or PrimaryKey Classes?
Thanks a lot for the help.
JPA specification contains such a requirement (JSR-317 secion 2.4 Primary Keys and Entity Identity):
The primary key class must be serializable.
If EclipseLink really doesn't enforce this requirement, it's an implementation detail of EclipseLink and I wouldn't recommend you to rely on it.
However, there are no requirements on serializability of entities, except for the following one which looks more like a recommendation than a requirement:
If an entity instance is to be passed by value as a detached object (e.g., through a remote interface), the
entity class must implement the Serializable interface.
Nothing is required to be serializable, but it seems it is requried by the spec (10x to axtavt) for primary keys, although there is no direct need for it.
Serialization is needed if the objects are transferred over-the-wire or persisted to disk, so I can't see the reason behind that decision. However, you should conform to it.
Primary key classes have to implement serializable and composite-ID class must implement serializable are two different questions.
I am going to answer you both, and hope it will help you to distinguish and understand holistically.
Primary key classes have to implement serializable:
Note: It could work without its iplementation also.
JPA specification contains such a requirement (JSR-317 secion 2.4 Primary Keys and Entity Identity):
The primary key class must be serializable.
However, there are no requirements on serializability of entities, so it's a recommendation than a requirement
exception:
If an entity instance is to be passed by value as a detached object (e.g., through a remote interface), the entity class must implement the Serializable interface.
Composite-ID class must implement serializable.
The id is used as a key to index loaded objects in the session.
The session object needs to be serializable, hence all objects referenced by it must be serializable as well.
In case of CompositeIds the class itself is used as the id.