hibernate search not tokenizing document id - tokenize

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.

Related

Is it possible to have optional property in ebean ORM

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.

How can I store Enum value as a String with Hibernate to SQL Server?

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.

Hibernate Search automatic update of composed fields

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.

What is mean by serializing from one VM to another when using JPA

I am reading JPA 2.0. I encounter a sentence that
We have used the transient modifier instead of the #Transient annotation so that
if the Employee gets serialized from one VM to another then the translated name
will get reinitialized to correspond to the locale of the new VM.
#Entity
public class Employee {
#Id private int id;
private String name;
private long salary;
transient private String translatedName;
// ...
public String toString() {
if (translatedName == null) {
translatedName = ResourceBundle.getBundle("EmpResources").getString("Employee");
}
return translatedName + ": " + id + " " + name;
}
}
What I understood is that when we use #Entity annotation and container encounter it then it call JPA provider that do the things. Like map id to ID column in database. Although we didn't mention the #Column annotation on the name and salary, but by default it maps to column NAME and SALARY in database. We used transient on translatedName so the JAP leave it as it is, not mapping applied to it. It's just a field in this class. But i am unable to get the understanding of the sentence
if the Employee gets serialized from one VM to another
Someone please explain it to me? Also tell me that what i defined above about the workflow of JAP is correct? Like what happening when container encounter #Entity annotation?
Thanks
When a class implements the java.io.Serializable interface, instances of this class are serializable. That means that the JVM can transform the object into a sequence of bytes. These bytes can be sent over the network, or saved on a disk, and can be read by another VM and transformed back into a Java object.
If a field has the transient Java keyword, it means that this field will be ignored by this serialization mechanism. The field won't be serialized.
A field annotated with #Transient is considered as a non-persistent field by JPA. It won't save it in the database, and it won't load it from the database. But it will be serialized if the object is sent to another JVM.
The Java transient keyword automatically makes a field #Transient. This means that a transient field, won't be serialized, and won't be saved by JPA either.
In the "JEE5 world" you can use detached entities as you would have used transfer objects. (I am not judging whether this is a good idea or not!)
Thus you can call for example a service method (e.g. EJB 3 SLSB method) that returns an instance of Employee remotely with the usual remote-call semantics regarding serialization.
It should be noted, that if an instance of Employee was serialized successfully, then your Java Runtime might be broken, as the class does not implement Serializable.
If you don't want to save the state of your entity arrtibute to DB and also don't want the state to get transferred to another jvm, then use Transient keyword.
If you don't want to save the state of your entity arrtibute to DB, but want the state to be transferred to another jvm, then use #Transient annotation.

Castle ActiveRecord Error With View: NHibernate.PropertyNotFoundException for generated key

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?