Hibernate Search - search in ManyToOne relation - hibernate-search

I have two indexed entities.
Player:
#Indexed
#Entity
public class Player {
#Field
private String firstName;
#ContainedIn
#ManyToOne
private Club playersClub;
}
and Club:
#Indexed
#Entity
public class Club {
#Fields({
#Field(store=Store.COMPRESS),
#Field(name = "sorting_name", analyze = Analyze.NO)
})
private String name;
#IndexedEmbedded(depth = 1)
#OneToMany(mappedBy = "playersClub")
private Set<Player> players;
}
Now when I search into ClubSearchService like this:
luceneQuery = queryBuilder
...
.onField("name").andField("players.firstName")
...
it works fine, but when I want search in other way(PlayerSearchService):
.onField("firstName").andField("lastName").andField("number").andField("country").andField("playersClub.name")
there is an error
org.hibernate.search.SearchException: Unable to find field playersClub.name in pl.domain.Player
Hibernate Search cannot search into ManyToOne item?

Yes it is possible to index ManyToOne relations as well.
In most simple cases you have one entity such as Club marked as #Indexed and then you want to index some of its fields and also embed via #IndexedEmbedded attributes from a related entity Player.
So far you got it right, and this is defining essentially the "flattened" schema for your club index.
The problem is that when defining the schema for the player index you marked firstname as an indexed field, but didn't instruct it to embed the relation to playersClub. Essentially you're missing the #IndexedEmbedded on this property.
To not be confused with the #ContainedIn annotation: this is purely to make sure that Hibernate Search will re-index the entities in which it is contained; it is not making both sides embedding each other in a symmetric way.
In more formal terms, the relation established by #IndexedEmbedded is a directed graph: if you want it to follow both directions you have to establish them both explicitly.

Related

Modelling a series of elements of the same entity in JPA (one-to-one relation)

I created an entity/table for a book, and I want to achieve that each element can reference another book to create a series.
I came up with this:
#Entity
public class Book {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer bookId;
#Lob
private String text;
#OneToOne
#JoinColumn(name = "book_id")
private Book previousPart;
}
However, the attribute previousPart is not seen as a column in my Database, while the others are. Is there a different annotation I have to use or is this the wrong way to model a relationship like this? Or do I have to use the type Integer instead of Book directly (I thought this was what the framework does internally)?
Try this way:
#OneToOne
#JoinColumn
private Book previousPart;
In your code you defined the book_id field as the join-column, which is an already existing column (the id itself), so actually you linked all entries to themselves.

JaVers, SpringDatat, JPA: Querying for Entity Update inside a Collection

I'm new to Stackoverflow, so I will make my best to conforms with usage. I was wondering if there were a way to get a complete list of changes/snapshots of a given Entity. For now it works well with edition of Singular Properties, as well as Addition and Deletion to Collection Property. But I'm unable to find when a Child Entity in the Collection Property was updated.
Given two Entities, and a LinkEntity:
#Entity
class Person {
#Id
Long id;
#OneToMany(mappedBy = "person", cascade = CascadeType.ALL)
Set<LinkAddress> addresses;
}
#Entity
class Address {
#Id
Long id;
#OneToMany(mappedBy = "address")
Set<Address> persons;
}
#Entity
class LinkPersonAddress {
#Id
Long id;
#ManyToOne
#ShallowReference
Person person;
#ManyToOne
#ShallowReference
Address address;
String linkType;
}
My use case is following. I get a specific Person by Id #1, and then mutate the type of specific Address (ie. HOME --> WORK). I save the Person back with the modified Set and let JPA Cascade my changes. Although all Spring Data Repositories for Person, Address, and LinkPersonAddress are annotated with #JaversSpringDataAuditable, I cannot retrieve this "update" using Javers QueryBuilder with the class Person and Id #1. It makes sense as I should query the class LinkPersonAddress instead, but how can I specify that I want only the changes from LinkPersonAddress relevant to Person with Id #1.
PS: Please apologize any typos in code snippets, as I didn't write it in my Dev Environment.
Let's start from the mapping. You did it wrong, Address is a classical ValueObject (see https://javers.org/documentation/domain-configuration/#value-object) not Entity. Because:
Address doesn't have its own identity (primary key genereted by a db sequence doesn't count)
Address is owned by the Person Entity. Person with its Addresses forms the Aggregate.
When you correct the mapping, you can use ChildValueObjects filter, see https://javers.org/documentation/jql-examples/#child-value-objects-filter

Nested query in mongodb using spring data

I am trying to use nested Mongodb query but it does not work.
It is similar to Spring data mongodb query for subdocument field
But suggestions mentioned there does not work.
Please find my documents below.
#Document
public class Ticket {
#Id
private String id;
#DBRef
#CascadeSave
private Customer customer;
// getters and setters
}
#Document
public class Customer {
#Id
private String id;
private String firstName;
// getters and setters
}
public interface TicketRepository extends MongoRepository<Ticket, String> {
public List<Ticket> findByCustomerFirstName(String firstName);
}
I tried both findByCustomerFirstName and findByCustomer_FirstName but it does not work. Any suggestions ?
These suggestions are right it should work...
Official docs explains it as you did it:http://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#repositories.query-methods.query-property-expressions
Property expressions can refer only to a direct property of the
managed entity, as shown in the preceding example. At query creation
time you already make sure that the parsed property is a property of
the managed domain class. However, you can also define constraints by
traversing nested properties. Assume a Person has an Address with a
ZipCode. In that case a method name of
List<Person> findByAddressZipCode(ZipCode zipCode);
creates the
property traversal x.address.zipCode
Just one thing, remove #Document from Customer and try it, Mongodb didn't support join queries (I'm not sure if now it does)... so you're document should be Ticket and it must have a embbebed document Customer as a inner object and not in a different document.

JPA #Jointable does not create column for id

I'm working on JBoss AS 7 using JPA to have a List of Beans in a Entity-Bean like this:
#Entity
class section {
#Id
#GeneratedValue
private Long id;
#ManyToOne
private List<Component> components;
// ...
The table to join the two tables gets created, but it does not contain an Id, which leads to JPA creating a unique-constrain on one of the columns (SECTION_ID). Which is not really what I want, because one section can have more than one component. One component can be used in more than one section too.
I already tried
#JoinTable(name="SECTION_COMPONENT",
joinColumns = {
#JoinColumn(name="section_id", unique = false)
},
inverseJoinColumns =
#JoinColumn(name="component", unique = false)
}
I guess JPA needs at least one unique column, so it just adds that to the last column if nothing else is specified. I'd be fine with adding a new column "id" to set up a primary (or unique) key. But I am not sure how to do that.
Thanks a lot for any help
The mapping is not correct: #ManyToOne in your case means that you have one component that has many sections:
#ManyToOne
private Component component;
According to your description, you need an #ManyToMany relationship:
#ManyToMany
private List<Component> components;

Behavior of JPA ORM of two entities with different CascadeType parameter?

I have a question regarding the JPA OR mapping between two persistent entities with a different CascadeType parameter on their annotations.
To clarify things, here is a simple example:
#Entity
public class Article
{
#Id
#GeneratedValue
private Long id;
#ManyToOne( cascade = CascadeType.ALL )
private Author author;
// Getters and Setters follow here
}
_
#Entity
public class Author
{
#Id
#GeneratedValue
private Long id;
#OneToMany( mappedBy = "author", cascade = CascadeType.REFRESH,
orphanRemoval = true )
private List< Article > articles;
// Getters and Setters follow here
}
As you can see, the "author" property has a different CascadeType set
(CascadeType.REFRESH) then the "articles" property (CascadeType.ALL). At first, I thought that a different CascadeType for the same property mapping is not allowed - but I tried it, and it is allowed.
Now, what I would like to know is, how does this behave? And makes such a (artifical) example any sense at all (as you see, this is more a theoretical question)?
Thanks a lot for your help!
cascade = CascadeType.XXX means: when you do the XXX operation on this object, automatically do the same XXX operation on the object(s) referenced by the association.
So, in your case, if you persist/merge/delete an article, it will also persist/merge/delete its author. This is thus very questionable. I don't think you really want that.
And when you'll refresh an author, it will also refresh its articles.
Note that if you refresh an article, it will refresh its author (because of CascadeType.ALL), and since the association form author to articles also has the REFRESH cascade type, it will also refresh all the articles of the author.