Adding fields transparently to all types - hibernate-search

Is there any integration point allowing to add a meta-field on all indexed documents transparently, right before they are indexed, similarly to _hibernate_class?
Currently using Hibernate 5.11

As discussed over the chat, the only option in Search 5 is to use the programmatic mapping API to add a class bridge to every single indexed entity type.
In Search 6, you can use the new programmatic mapping API to add a type bridge to the Object type, and it will be applied to every type. It will also be applied to embedded types, though, so that may not be what you're after.

Related

How can I reuse a field in several bridges in Hibernate Search 6?

In Hibernate Search 5 I had several custom bridges that populated the same field. That was handy so that I can perform a query on just one field. Now if I try to do it I receive this error:
HSEARCH600034: Duplicate index field definition: 'attributes'. Index field names must be unique. Look for two property mappings with the same field name, or two indexed-embeddeds with prefixes that lead to conflicting index field names, or two custom bridges declaring index fields with the same name.
I have not found a way to get an existing field from the PropertyBinding Context when implementing the PropertyBinder, only the documented way to add new fields:
IndexFieldReference<String> attributesField = schemaElement
.field("attributes", f -> f.asString())
.toReference();
Am I missing something or is no longer possible and I need to add new fields?
How can I reuse a field in several bridges in Hibernate Search 6?
At the moment, you cannot.
This limitation is a side effect from the (many) sanity checks that Hibernate Search 6 performs on startup, which prevent common mistakes and indirectly allow a more intuitive behavior in the Search DSL.
Your options are pretty much this:
Either you refactor your bridges to regroup all code that contributes to the same field in a single bridge (either a TypeBridge, or a PropertyBridge applied to a non-persisted getter that returns an aggregated list of all values you're interested in).
Or you change your bridges to each contribute to its own field, and change your search code to target all these fields at once; most (if not all) predicates allow targeting multiple fields in the same predicate.
The second solution is also the recommended way of indexing, since it produces more accurate relevance scores.
EDIT: If you go for solution 2, this (not yet implemented) feature might be of interest to you: https://hibernate.atlassian.net/browse/HSEARCH-3926

How to validate multiple Typo3 action parameters in combination?

The Typo3 documentation describes #Validate annotations which can be used to validate parameters for a single controller action:
https://docs.typo3.org/m/typo3/book-extbasefluid/master/en-us/9-CrosscuttingConcerns/2-validating-domain-objects.html
However, it is only described how to add a custom validator for a single parameter. It is possible to add multiple validation annotations, but then again each of them can validate just a single parameter, not multiple parameters in combination.
First question: It is possible to add a validator which checks multiple parameters, or even all parameters, of a specific controller action?
Of course the obvious workaround is to combine multiple arguments in a single argument, using e.g. an array or an object. But this is especially annoying if the arguments themselves are already (independent) model objects.
Second question: If the answer to the first question is "it's impossible", what is the recommended way to combine the arguments of a controller action?
(e.g.: Should one use an array? That seems to be not preferred in Typo3 due to the lack of type safety and other features. Should one create a class? But which kind of class would that be? A Utility class? A Model class? But that model class would then need suppressed persistence? This seems to be all messy.)
I'm using version 9.5 of Typo3, but if things are different in version 10, that would be interesting as well.
To the best of my knowledge I suggest using a data transfer object (DTO) for this purpose.
If your models have to be validated in combination, but do not belong to any other entity, combining them in a DTO is probably the best way to go. Consequently the validation logic is then clustered in a single validator.
See also this blog post about DTOs: https://usetypo3.com/dtos-in-extbase.html

Classical navigation properties vs owned types in aggregates

After release of EF Core 2.2 it is now possible to have both single and collection values of owned types.
In contrast to classical navigational properties owned types are always included in the entity, so owned types looks like a natural way of describing the shape of an aggregate.
Are there any DDD related use cases where classical navigation properties are still better?
Update 1
Prior to 2.2 I was able to call modelBuilder.Entity<OwnedType> and configure alternative key.
Now with 2.2 I started getting errors during migration: primary key is not defined for the entity. However, ReferenceOwnershipBuilder class which is passed as a parameter to buildAction lambda in method OwnsOne does not contain HasAlternateKey. This is currently a known limitation.
Update 2
Currently owned types do not support inheritance. This may be critical for some use cases.

OData REST API where table has columns unique to customer

We would like to create an OData REST API. Our data model is such that each customer has their own database. All database objects have the same definition across all customer databases, with the exception of a single table.
The customer specific table we will call Contact. When a customer adds a column the system creates a column with a standardised name with a definition translated from options selected by the user in the UI. The user only refers to the column data by a field name they have specified to enable the user to be able to generate friendly queries.
It seems to me that the following approaches could be used to enable OData for the model described:
1) Create an OData open type to cater for the dynamic properties. This has the disadvantage of user requests for a customer not providing an indication of the dynamic properties that can be queried against. Even though they will be known for the user (via token authentication). Also, because dynamic properties are a dictionary, some data pivoting and inefficient query writing would be required. Not sure how to implement the IQueryable handling of query options for the dynamic properties to enable our own custom field querying.
2) Create a POCO class with e.g. 50 properties; CustomField1, CustomField2... Then somehow control which fields are exposed for use in OData calls. We would then include a separate API call to expose the custom field mapping. E.g. custom field friendly name of MobileNumber = CustomField12.
3) At runtime, check to see if column definitions of table changed since last check. If have, generate class specific to customer using CodeDom and register it with OData. Aiming for a unique URL for each customer. E.g. http://domain.name/{customer guid}/odata
I think the ideal for us is option 2. However, the fact the CustomField1 could be an underlying SQL data type of nvarchar, int, decimal, datetime, etc, there are added complications.
Has anyone a working example of how to achieve what has been described, satisfactorily?
Thanks in advance for any help.
Rik
We have run into a similar situation but with our entire dataset being unknown until runtime. Using the ODataConventionModelBuilder and EdmModel classes, you can add properties dynamically to the model at runtime.
I'm not sure whether you will have to manually add all of the properties for this object type even though only some of them are unknown or whether you can add your main object and then add your dynamic ones afterwards, but I guess either would be workable.
If you can get hold of which type of user it is on the server, you could then add only the properties that you are interested in (like option 3 but not having to CodeDom).
There is an example of this kind of untyped OData server in the OData samples here that should get you started: https://github.com/OData/ODataSamples/tree/master/WebApi/v4/ODataUntypedSample
The research we carried out actually posed Option 1 as the most suitable approach for some operations. i.e. Create an SQL view that unpivots the data in a table to a key/value pair of column name/column value for each column in the table. This was suitable for queries returning small datasets. This was far less effort than Option 3 and less confusing for the user than Option 2. The unpivot query converted the field values to nvarchar (string) values and thus meant that filtering in the UI by column value data types was not simple to achieve. (If we decide to implement this ability, I believe this can be achieved by creating a custom attribute that derives from EnablQueryAttribute, marking the controller action with it and manipulate the IQueryable before execution).
However, we wanted to expose a /Contacts/Export endpoint that when called would output the columns from a table with a fixed schema joined on a table with a client specific schema and output to a CSV file. All the while utilising the OData supported filter syntax. One of our customer databases has more than 12 million rows of data and is made up of approximately 30 columns.
To achieve this it looks like our best bet would have been to work with the Microsoft.OData.Core.UriParser.UriQueryExpressionParser class, unfortunately Microsoft in their wisdom have declared this as internal, as well as many of it's dependants.
Walking an abstract syntax tree built from OData supported query options and applying our own visitor to each node to build some dynamic Linq query/SQL seems like a possible solution.
For the time-being we will simply implement a cut-down set of supported $filter criteria without the support for grouping parenthesis.

How to use the exists keyword in Spring Data to check for the existence of an entity?

How do I use the 'exists' keyword in Spring Data in a query method?
I would like to have a method like this:
public interface ProfileRepository extends JpaRepository<Profile, Long> {
boolean existsByAttribute(String attribute);
}
where Attribute is a field of the Profile.
A workaround would be to use a custom-implementation. But the appendix defines exists as keyword. Could someone give me an example how to use this keyword?
Documented keywords are intended to be used in combination with a property reference. Thus, the semantics of EXISTS in this case are that it checks whether the property exists. Note, that the part of the documentation is pulled it from Spring Data Commons and the keyword being listed there doesn't mean it's supported in Spring Data JPA (indicated in the first paragraph of the section you linked). Exists is not supported by Spring Data JPA as it only makes sense in MongoDB for example as there's a difference between a field not present entirely and the field available with a logically null value.
So what you're looking for seems to be around the (Is)Null keyword with the current limitation that it would return objects and you'd have to check the returned list for content. There's a ticket to add support for projections for derived query methods which you might wanna follow for further progress.