Can the #Id and #DocumentId Annotations Be Specified on Different Fields? - hibernate-search

I see the #Id and #DocumentId annotations in the code examples of the Hibernate Search Reference Guide always appear together on the same field, such as follows.
public class Book {
#Id
#GeneratedValue
#DocumentId
private Integer id;
//...
}
I want to know whether it is possible to use the #Id and #DocumentId annotations on different fields, such as follows?
public class Book {
#Id
#GeneratedValue
private Integer id;
#DocumentId
private Integer isbn;
//...
}
The purpose of this requirement might be using the #Id annotation for performing Hibernate queries, and using the #DocumentId annotation for performing Hibernate Search queries.
Thanks.

So, the answer is yes, you can do it. We even have a unit test just for that.
Next question is: would I recommend it?
Not really. Keep the #DocumentId on your #Id and add a #Field on your isbn field. IMHO, it's far more intuitive and it will allow you to search on the isbn. There's no good reason for you to rely on such a corner case.

Technically the #DocumentId is optional, it will default to use the same field as #Id. I guess we should remove it from some examples to clarify that we generally don't expect you to use it.
So the #DocumentId exists specifically to allow you to override the default choice.

Related

Will my Spring Data Jpa method return all foreign fields?

If I have a table like this :
Client
private Long int;
private String name;
#ManyToOne(mappedBy="otherField")
private Address addresses;
And I Create a repository that extends JPA Repository. Given the name of the client, I want to get as results also the Address Table fields.
Using the method
Client findByName(String name)
Will my this also return all the fields that are on the Address Table ?
Like:
Address
private Long id;
private String city;
private Int code;
private String street;
From the docs
The Hibernate recommendation is to statically mark all associations
lazy and to use dynamic fetching strategies for eagerness. This is
unfortunately at odds with the JPA specification which defines that
all one-to-one and many-to-one associations should be eagerly fetched
by default. Hibernate, as a JPA provider, honors that default.
So Hibernate behaves the same as JPA:
OneToMany: LAZY
ManyToOne: EAGER
ManyToMany: LAZY
OneToOne: EAGER
Also take a look at the JPA sepcifications here.

JPA Simple ForeignKey relationship

Is it possible to create a basic FK relationship in JPA without involving the full entity target object?
As an example, imagine I have an entity:
#Entity(name = "Mechanic")
public class Mechanic {
#Id
private Long id;
//...
and a Car that I want to reference a Mechanic.id:
#Entity(name = "Car")
public class Car {
//...
#NotNull
private Long mechanic_id;
From an Object perspective, this would be a unidirectional, one to one relationship with the Car requiring a Mechanic.id and the Mechanic not needing any back reference to Car.
All I want out of this is to store the Mechanic.id ONLY. For the purposes of this question it is not useful to have a #OneToOne (or #OneToMany etc) relationship with the entity reference, I'm explicitly trying to avoid that but still retain the underlying integrity that a FK will provide.
JPA 2 and I'm using EclipseLink.

Questions regarding mongodb sub-document and spring-data-mongo querying

I'm still trying to get my hands around mongodb and how best Entities can be mapped. if you take for example: the entity user and the entity addresses. there could be one-to-many when someone is coming from jpa background. Here in mongo i don't want to use dbref. So addresses are in a Set collection in user.
Supposing i was using spring-data-mongo:
Question 1 : should both User and Address have the #Document annotation?Or just User?
Question 2 : what is the best way to query for addresses of a user. It is possible at first place? Because right now I query to get the User by username or Id and then get the addresses of the user.Can I query directly for sub-document? if yes how is it done using spring-data-mongo Criteria Query:
#Document
public class User{
#Id
private Long ID;
private String username;
private Set<Address> addresses = new HashSet<Address>();
...
}
#Document
public class Address {
#Id
private Long ID;
private String city;
private String line1;
...
}
Question 1: No, #Document is not strictly necessary at all. We just leverage this on application startup if you activate classpath-scanning for document classes. If you don't the persistence metadata scanning will be done on the first persistence operation. We traverse properties of domain objects then, so Address will be discovered.
Question 2: You'll have to read the User objects entirely as MongoDB currently does not allow returning sub-documents. So you'll have to query for the entire Userdocument but can restrict the fields being returned to the addresses field using a fieldSpec on the Query object or the repository abstraction's #Query annotation (see ref docs).

JPA Composite Primary Key generating

I have simple entity class (irrelevant methods omitted):
#Entity
#Table(name="CONNECTIONS")
public class Connection implements Serializable {
#Id private Long id_track;
#Id private Long id_carrier;
#Id private Date date_out;
#Id private Time time_out;
private Date date_in;
private Time time_in;
private Double price;
...
}
I expect that JPA (in my case Eclipse implementation) creates TABLE CONNETIONS with composite primary key that consists of id_track, id_carrier, date_out and time_out columns but it adds addidional column id (of type integer) What do I do wrong?
I can not reproduce this. Are you sure JPA is creating your table?
Also ensure you have recompiled and redeployed your code.
Perhaps enable logging, and include what JPA provider and version you are using.
Are you using Glassfish?

How to create a composite primary key which contains a #ManyToOne attribute as an #EmbeddedId in JPA?

I'm asking and answering my own question, but i'm not assuming i have the best answer. If you have a better one, please post it!
Related questions:
How to set a backreference from an #EmbeddedId in JPA
hibernate mapping where embeddedid (?)
JPA Compound key with #EmbeddedId
I have a pair of classes which are in a simple aggregation relationship: any instance of one owns some number of instances of the other. The owning class has some sort of primary key of its own, and the owned class has a many-to-one to this class via a corresponding foreign key. I would like the owned class to have a primary key comprising that foreign key plus some additional information.
For the sake of argument, let's use those perennial favourites, Order and OrderLine.
The SQL looks something like this:
-- 'order' may have been a poor choice of name, given that it's an SQL keyword!
create table Order_ (
orderId integer primary key
);
create table OrderLine (
orderId integer not null references Order_,
lineNo integer not null,
primary key (orderId, lineNo)
);
I would like to map this into Java using JPA. Order is trivial, and OrderLine can be handled with an #IdClass. Here's the code for that - the code is fairly conventional, and i hope you'll forgive my idiosyncrasies.
However, using #IdClass involves writing an ID class which duplicates the fields in the OrderLine. I would like to avoid that duplication, so i would like to use #EmbeddedId instead.
However, a naive attempt to do this fails:
#Embeddable
public class OrderLineKey {
#ManyToOne
private Order order;
private int lineNo;
}
OpenJPA rejects the use of that as an #EmbeddedId. I haven't tried other providers, but i wouldn't expect them to succeed, because the JPA specification requires that the fields making up an ID class be basic, not relationships.
So, what can i do? How can i write a class whose key contains #ManyToOne relationship, but is handled as an #EmbeddedId?
I don't know of a way to do this which doesn't involve duplicating any fields (sorry!). But it can be done in a straightforward and standard way that involves duplicating only the relationship fields. The key is the #MapsId annotation introduced in JPA 2.
The embeddable key class looks like this:
#Embeddable
public class OrderLineKey {
private int orderId;
private int lineNo;
}
And the embedding entity class looks like this:
#Entity
public class OrderLine{
#EmbeddedId
private OrderLineKey id;
#ManyToOne
#MapsId("orderId")
private Order order;
}
The #MapsId annotation declares that the relationship field to which it is applied effectively re-maps a basic field from the embedded ID.
Here's the code for OrderId.