When using Ebean, let's say, I have the ORM class as follows:
#Entity
public class Student {
#id
private UUID id;
String age;
}
Assuming that the age is a nullable column in the database, we have to always check the null on this string. Is it possible to have age as an optional property to make this explicit?
#Entity
public class Student {
#id
private UUID id;
Optional<String> age;
}
Is it possible to have age as an optional property to make this explicit?
No, it is not possible.
Note that we could modify Ebean to support this but we do not do that because we don't think this is the correct thing to do.
The reason is because it is generally expected that Optional isn't used for ANY FIELD in java. Optional is expected to be used as a return type or method parameter but NOT for a field. IntelliJ will show a warning on any field that uses an Optional type.
So Ebean does not support Optional fields because it would then be inconsistent with that general expectation that Optional should not be used this way.
Related
I'd like to mark some Room entity's properties as internal. E.g.
#Entity(tableName = "users")
class User {
// ...
#ColumnInfo(name = "admin_id")
internal var adminId: String? = null
}
However, this produce compile errors like:
Error:(10, 1) error: Cannot find getter for field.
The only way how to make this works seems to use lateinit modifier, though, it can't be used for nullable neither primitive fields.
I've tried a "hack": a private field with internal getter/setter, but that doesn't work either.
The compiled generated version obviously adds some suffix to the generated methods (setAdminId$sdk_debug) that doesn't work with room. The "lateinited" field's setters/getters have this suffix too, but the field stay itself public.
Is there any way how to make columns internal?
It seems its getting supported in latest Room 2.5.0-alpha01
Old answer: I didn't solve this and I have to define new set of entities and mapper between them.
The internal names get mangled by Kotlin, so I made it work by just making sure the correct name is used with #JvmName:
#Entity(tableName = "users")
class User {
// ...
#ColumnInfo(name = "admin_id")
#get:JvmName("adminId")
internal var adminId: String? = null
}
Note: This might make it easier to accidentally use this from Java then.
So I'm having an Enum-property in an Entity bean:
#Entity
#Table(name = "fileAttachment")
public class FileAttachment
// other properties..
#Enumerated(EnumType.STRING)
FileAttachmentType type;
// getters and setters
However, when I persist the bean, the value in that column is shown as a number such as 0 or 1 or 2.
If I println the value of the enum just before persisting the bean with EntityManager, the value prints out as String, such as INVOICE but in the SQL Server table that row has value 2 for example on the fileAttachmentType-column. What else do I need to configure? I thought the EnumType.STRING would do the trick.
Do you create the table in DB by yourself or rely on Hibernate in it?
If first make sure the column type suits for strings storing.
If second try to use annotation like
#Column(columnDefinition = "enum('VALUE1','VALUE2')")
Ok, in this case things worked out when I added the annotation: #Enumerated(EnumType.STRING)
to the getter of that field and NOT to the actual field.
In another project it works when the annotation is on the field and not anywhere else... so, as far as I comprehed, the answer is the good old "for some reason", but it works now.
If someone would comment the reason for this, I'll update the answer.
EDIT: The reason was found. There was already an annotation on a getter in that Entity class. That's why the annotation on a field didn't work. It happens to be so, that you should either have annotations ONLY on fields OR ONLY on getters. Not annotations on both.
Does somebody know if there is a workaround for enabling hibernate-search to tokenize the #DocumentId of an entity? According to the docs: "By design, an id has to be stored and must not be tokenized. It is also always string encoded, even if the id is a number."
Just add an additional #Field annotation. Any field can be indexed multiple times, either by using #Fields or in the case of document id either by adding an additional #Field to the property annotated with #DocumentId resp #Id, for example:
#Entity
#Indexed
public class Animal {
#Id
#Field(name="tokenized_id")
private String id;
// ...
}
no need for a transient field.
The solution is to create a transient field, and on getter method return your filed annotated with #Id or #DocumentId, then you can apply your tokenizers/filters on that transient field. After all are set, you can create your query and search on transient field rather than your entity primary key.
I have a Person entity with multiple name related properties (firstName, lastName, title).
All the name related properties should be stored in a single lucene index field "fullName".
#Indexed
#Entity
public class Person {
...
private String firstName;
private String lastName;
private String title;
#Field(store=Store.NO, index=Index.TOKENIZED)
public String getFullName() {
return firstName + " " + lastName + " " + title;
}
}
The only problem I'm facing is to automatically update the fullName in the index when a name related property is updated.
Is there some way to tell Hibernate Search that fullName is a composed field and must be updated when one of the parts changes? Maybe something like this?
#ComposedOf({"firstName", "lastName", "title"})
Thank you!
There are several solutions for your problem and it the solution you are choosing is probably a matter of taste (you might also apply a combination of them):
Check the property _hibernate.search.enable_dirty_check_ and make it sure it is set to false in your case. The default is true. See the online docs for more information - http://docs.jboss.org/hibernate/stable/search/reference/en-US/html_single/
Add the #Field annotation also to firstName, lastName and title. You get a bigger index size, but often that does not matter. As a side effect the dirty checking will work (assuming btw that your JPA annotations are correct. For example I am assuming getFullName is transient)
Use a class bridge and optionally remove getFullName. Using a class bridge will also automatically disable the dirty check optimisation
#Indexed
#Entity
public class Person {
...
#Field(name="fullName") String firstName;
#Field(name="fullName") String lastName;
#Field(name="fullName") String title;
}
This is possible as you have chosen TOKENIZED and I'm assuming your analyzer is set to split the tokens on whitespace as you're adding whitespace to separate them: you can have multiple repetitions of a same field, the result is almost the same as splitting the compound terms
(I say almost as it won't be able to determine ordering of terms in case you need a PhraseQuery looking for a specific order of keywords).
For more complex cases you would use a ClassBridge which disables the dirty-checking optimisation which has been annoying you in this case: Hibernate Search tracks if any persistent field was actually written to to decide if it can skip expensive reindexing operations but is then unable to detect such tricks.
I'm mapping a view using ActiveRecord, which means I need a primary key. I don't have one, so I'm using ROW_NUMBER() to create one in the view definition to placate the system. However, I don't seem to know how to map it properly. I'm getting:
Could not find field 'stupidID' in class 'blah_blah'
NHibernate.PropertyNotFoundException: Could not find field 'stupidID' in class 'blah_blah'
My mapping looks like this. There is no
public long? stupidID;
[PrimaryKey("StupidId", Access = PropertyAccess.NosetterLowercaseUnderscore)]
public long? StupidId
{
get { return stupidID; }
}
Can anyone see what I'm missing?
NosetterLowercaseUnderscore means that by convention a prefix '_' is used and it's lowercase, so the field should be called _stupidid instead of stupidID.
Also, the PK shouldn't be a nullable type. I'd use long instead of long?