Hibernate Search automatic update of composed fields - lucene

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.

Related

Model Validation in .Net Core

Are the DataAnnotations executed in the same order as they are specified or in a random order.
Example :
public class Model1
{
[Required]
[Range(3,45,ErrorMessage="out of range")]
[emailaddress]
public string email_id {get;set;}
}
Does the annotations are checked in the same way as declared or how?
it's probably checked in the order of logic and performance, not the order you wrote it. If the field is required, it would be pointless to check Range first. For controls at the same level, it is checking according to performance. it checks the least costly one first so that it does not spend much effort in the case it does not comply with the condition.

How to structure object: OOP, composition

I have an object, let's call it a Request, that has associations to several other objects like:
Employee submitter;
Employee subjectsManager;
Employee pointOfContact;
And several value properties like strings, dates, and enums.
Now, I also need to keep track of another object, the subject, but this can be one of 3 different types of people. For simplicity let's just talk about 2 types: Employee and Consultant. Their data comes from different repositories and they have different sets of fields, some overlapping. So say an employee has a
String employeeName;
String employeeId;
String socialSecurityNumber;
Whereas a consultant has
String consultantName;
String socialSecurityNumber;
String phoneNumber;
One terrible idea is that the Request has both a Consultant and an Employee, and setSubject(Consultant) assigns one, setSubject(Employee) assigns the other. This sounds awful. One of my primary goals is to avoid "if the subject is this type then do this..." logic.
My thought is that perhaps an EmployeeRequest and a ConsultantRequest should extend Request, but I'm not sure how, say, setSubject would work. I would want it to be an abstract method in the base class but I don't know what the signature would be since I don't know what type the parameter would be.
So then it makes sense to go at it from an interface perspective. One important interface is that these Request objects will be passed to a single webservice that I don't own. I will have to map the object's fields in a somewhat complex manner that partially makes sense. For fields like name and SSN the mapping is straightforward, but many of the fields that don't line up across all types of people are dumped into a concatenated string AdditionalInfo field (wump wump). So they'll all have a getAdditionalInfo method, a getName, etc, and if there's any fields that don't line up they can do something special with that one.
So that makes me feel like the Request itself should not necessarily be subclassed but could contain a reference to an ISubjectable (or whatever) that implements the interface needed to get the values to send across the webservice. This sounds pretty decent and prevents a lot of "if the subject is an employee then do this..."
However, I would still at times need to access the additional fields that only a certain type of subject has, for example on a display or edit page, so that brings me right back to "if subject is instance of an employee then go to the edit employee page..." This may be unavoidable though and if so I'm ok with that.
Just for completeness I'll mention the "union of all possible fields" approach -- don't think I'd care to do that one either.
Is the interface approach the most sensible or am I going about it wrong? Thanks.
A generic solution comes to mind; that is, if the language you're using supports it:
class Request<T extends Subject> {
private T subject;
public void setSubject(T subject) {
this.subject = subject;
}
public T getSubject() {
return subject;
}
}
class EmployeeRequest extends Request<Employee> {
// ...
}
class ConsultantRequest extends Request<Consultant> {
// ...
}
You could similarly make the setSubject method abstract as you've described in your post, and then have separate implementations of it in your subclasses. Or you may not even need to subclass the Request class:
Request<Employee> employeeRequest = new Request<>();
employeeRequest.setSubject(/* ... */);
// ...
int employeeId = employeeRequest.getSubject().getEmployeeId();

NHibernate - truly dynamic sorting

Using NHibernate, I need to be able to configure my application to sort a specific collection of entities exactly as needed.
The configurable sort:
can involve multiple properties
can specify the sorted properties in any order
can specify asc/desc on the sorted properties
can sort by custom properties (i.e. there is no corresponding SQL/C# property - it is calculated)
This functionality is inherited from an existing app where parts of the SQL are specified by an administrator and the SQL statement is built/executed dynamically.
Every time I try thinking through a solution I start getting in muddy waters with all kinds of alarms going off in my head regarding maintainability, performance, scalability, security, etc..
For example, I figure the admin can specify a comma delimited string like so:
"Date asc, FirstName asc, LastName desc"
I can split the string and go through a loop matching the property/sort pairings in a case statement and calling .AddOrder(Order.Asc("FirstName")) as necessary. But then, how do I handle custom properties? I could allow the user to specify SQL for calculating custom properties and then allow the user to sort on those like they would FirstName, but I'm seemingly back at dirty/kludge again.
Is there a clean/appropriate way to handle this requirement?
After much thought and a stroke of luck, I may have a solution.
public class CustomOrder : Order
{
private string customOrderSql;
public CustomOrder(string customOrderSql) : base("", true)
{
this.customOrderSql = customOrderSql;
}
public override NHibernate.SqlCommand.SqlString ToSqlString(
ICriteria criteria, ICriteriaQuery criteriaQuery)
{
return new NHibernate.SqlCommand.SqlString(this.customOrderSql);
}
}
I can pass a custom sort string to my repository where I add my CustomOrder as follows:
.AddOrder(new CustomOrder(customSort))
I still can't sort by custom properties but maybe I can get away with applying case statements in the order by clause. I'm still open for better suggestions if they exist.

Keeping NHibernate from loading some fields

This is a follow on question to My earlier question on lazy loading properties. Since the application is an enhancement to a production application in a fairly major enterprise, and it currently running using NHib 1.2, upgrading to version 3 is not going to happen, so the suggested answer of using Lazy Properties in 3.0 won't work for me.
To summarize the problem, I have simple database with 2 tables. One has about a dozen simple fields, plus a one to many relation to the second table as a child table. Two of the fields are very large blobs (several megabytes each), and I want to, effectively, lazy load them. This table has about 10 records, and they populate a grid at start up, but access to the large blobs are only needed for whatever row is selected.
The object structure looks something like this:
[Serializable]
[Class(Schema = "dbo", Lazy = false)]
public class DataObject
{
[Id(-2, Name = "Identity", Column="Id")]
[Generator(-1, Class="native")]
public virtual long Identity { get; set;}
[Property]
public string FieldA { get; set;}
[Property]
public byte[] LongBlob {get; set;}
[Property]
public string VeryLongString { get; set;}
[Bag(-2, Cascade=CascadeStyle.All, Lazy= false, Inverse=true)]
[Key(-1, Column="ParentId")]
[OneToMany(0, ClassType=typeof(DataObjectChild))]
public IList<DataObjectChild> ChildObjects { get; set;}
}
Currently, the table is accessed with a simple query:
objectList = (List<DataObject>) Session.CreateQuery("from DataObject").List<DataObject>();
And that takes care of everything, including loading the child objects.
What I would like is a query to do exactly the same thing, except select a list of the properties of the DataObject that includes everything EXCEPT the two blobs. Then I can add custom property Getters that will go out and load those properties when they are accessed.
So far, I have not been successful at doing that.
Things I have tried:
a) constructing an HQL query using a SELECT list.
It looks something like this:
objectList = (List<DataObject>) Session.CreateQuery(
"SELECT new DataObject " +
"(obj.Identity, obj.FieldA) " +
"from DataObject as obj")
That works, though I have to add a constructor to the DataObject that will construct it from fields I select, which is rather cumbersome. But then it doesn't load and expand the list of child objects, and I can't figure out how to do that easily (and don't really want to - I want to tell NHib to do it.)
b) removing the [Property] attribute from the two fields in the object definition. That keeps the NHibernate.Mapping.Attributes from mapping those fields, so they don't get included in the query, but then I have no way to access them from NHib at all, including writing them out when I go to save a new or modified DataObject.
I'm thinking there has to be an easier way. Can somebody point me in the right direction?
Thanks
I think you're on the right path. However, you're going to have to do more manual work since you're using a very old version of NHibernate. I would fetch projections of your entities that contain only the columns you want to eagerly load. Then when the UI requests the large blob objects, you're going to have to write another query to get them and supply them to the UI.
Another option would be to have a second class (e.g. SmallDataObject) with the same mapping (but without the blobs) and use that for the list. When editing a list item you would load the class with the blobs using the id of the selected list item.
In any case, modifying the mapping after the creation of the SessionFactory is not possible, so you cannot get rid of the mapped properties on demand.

Complex Searching with NHibernate

I am curious about what methods do you use for complex searching with NHibernate ?
I am using Ayende's
What is yours ?
Thanks for your advices and answers.
If we have a complex dynamic search, we will usually construct a SearchParameter object and then pass that into a method that will build our criteria for us.
For example, if we were searching for a person we might have a search object that looks like this:
public class PersonSearchParameters
{
public string FirstName {get; set;}
public string LastName {get; set;}
public ICriteria GetSearchCriteria()
{
DetachedCriteria query = DetachedCriteria.For(typeof (Person));
//Add query parameters
Return query;
}
}
Then for each type of search, we'll be able to create the single criteria from the class, or we could have multple search parameter classes and chain them together
We use HQL, but we're still trying to wrap our heads around the Criteria API for complex queries. We have to manage a lot of duplication when using HQL.
I use pretty much Ayende's too jsut a bit more complex, what do you want to do that you cant do with that?
Basically what we added is that we have an interface where we define all the fields where we want to search and we call this when we are about to make the search which means that we can easily change what we are searching for.
Also we are using Active Record in the project ( on top of Hibernate) and tis pretty cool, loads of tasks gets simplified , thou the lack of docs does hurt sometimes
Cheer