Hibernate OGM mapping to subcollection - mongodb

I have an collection as following
application
* _id
* name
* desc
* settings
** _id
** magento
*** name
*** keys
I use the following object to map the document
#Entity
#Table(name = "applications")
public class ApplicationEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Type(type = "objectid")
private String id;
#Column(name = "applicationName")
private String name;
#Column(name = "desc")
private String desc;
#Embedded
#Column(name = "settings.magento")
private MagentoSettings magentoSettings;
However, the object "MangetoSettings" could not be mapped and it return null.
My question is that how I can map sub document (magento) without declare the parent (settings) in my object?
Let's say the "Settings" document contains only "Magento" and it would be wasted if declare "Settings" object with single property.
Thanks

I found the answer in the Jboss Hibernate doc here
You can override the column name used for a property of an embedded object. But you need to know that the default column name is the concatenation of the embedding property, a . (dot) and the embedded property (recursively for several levels of embedded objects).
AttributeOverrides({
#AttributeOverride(name="name", column=#Column(name="settings.magento.name")),
#AttributeOverride(name="key", column=#Column(name="settings.magento.key"))
})
private MagentoSettings magentoSettings;
Thanks

Related

Sorting on embedded entity name in hibernate search

I have the following Entity definitions.
public class Order {
#Id
#DocumentId
private Long id;
#Field
#IndexedEmbedded(includePaths = {"name"})
#OneToOne
#JoinColumn(name = "ACCOUNT_ID")
private Account account;
// the rest are omitted for brevity purpose
}
public class Account {
#Id
#DocumentId
private Long id;
#SortableField(forField = "name_Sort")
#Field(name = "name_Sort", store = Store.YES, normalizer= #Normalizer(definition = SearchConstants.LOWER_CASE_NORMALIZER))
#Column(name = "NAME")
private String name;
}
If I search on Order and want to have the search results sorted by account name, is there good way of doing so possibly using the embedded indexed annotation? I know we can do it by adding an extra string field in Order that is called accountName, then just add sorting annotation on top of that. Is it possible to achieve this without specifying the sorting annotation in Order but just use the sorting annotation that is already defined in Account?
Change this:
#IndexedEmbedded(includePaths = {"name"})
To this:
#IndexedEmbedded(includePaths = {"name", "name_Sort"})
Then you can use the field account.name_Sort for sorts on orders:
QueryBuilder builder = fullTextSession.getSearchFactory()
.buildQueryBuilder().forEntity( Order.class ).get();
Query luceneQuery = /* ... */;
FullTextQuery query = s.createFullTextQuery( luceneQuery, Order.class );
query.setSort(
builder.sort().byField("account.name_Sort").createSort()
);
List results = query.list();

Will JPA eagerly fetch non-entity attributes?

I want to know if attributes such as Int or Varchar2 are fetched eagerly or lazily when creating a regular query.
#Entity
#Table(name = "ROOM")
public class Room implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name = "room_id")
private Integer id;
#Column(name = "number")
private String number;
#Column(name = "capacity")
private Integer capacity; //Will this be fetched eagerly???
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "building_id")
private Building building;
...
...
...
}
Basically:
Room room = getRoomById(5); // select room from Room room where room.id = 5;
Integer roomCap = room.getCapacity(); //Will this create another query?
Or will it be inside the room object already?
The fetching strategies eager or lazy apply to relationships or associated entities where you want to load the data from another table and not to the columns that are part of the same entity or table. Columns or fields that belong to the same entity or table are fetched when you retrieve the entity and no separate query is fired.
when use lazy loading after data call on db after that you want to this object inside object your query go to db and execute db.
When you eager attribute get All element thats object

How to show 2 different type of mappings between 2 entity classes, holding each other's reference

The mappings between the 2 tables(Department and Employee) is as follows (Link for the image showing mapping is also provided):
Every department has one and only one department head.
Every department can have more than one employee.
dept_id and empId are primary keys of their respective tables.
dept_head(It is the Employee Id) and dept are foreign keys of their
respective tables.
Mapping Employee and Department table
I created entity classes for the above 2 tables (The structure is provided below).
Employee Class:
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "empId")
private Integer empId;
#Size(max = 45)
#Column(name = "name")
private String name;
#Size(max = 45)
#Column(name = "address")
private String address;
#Size(max = 45)
#Column(name = "grade")
private String grade;
#Size(max = 45)
#Column(name = "email")
private String email;
#JoinColumn(name = "dept", referencedColumnName = "dept_id")
#ManyToOne
private Department deptartment;
.. ...
}
Department class:
public class Department implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 8)
#Column(name = "dept_id")
private String deptId;
#Size(max = 45)
#Column(name = "name")
private String name;
#JoinColumn(name = "dept_head", referencedColumnName = "empId")
#OneToOne
private Employee deptHead;
#OneToMany(mappedBy = "deptartment")
private List<Employee> employeeList;
....
...
}
If I am adding mappedBy in Employee Class (like I did in Department), to show OneToOne mapping between empId and deptHead,the code is compiling and running. However, If I do not add the mappedBy statement in Employee class, as the above code shows, the code still compiles and runs fine.
I would want to know why the code above works even if I am not providing mappedBy in employee class.
If anybody can help me clearing the above doubts and explaining the logic behind its working would be great as I am new to this.
It is not quite clear where you tried to user it with and without the mappedBy attribute.
But if I get your question correctly, you ask why you can have only one or both sides annotated?
It depends on which side is the source and destination of your relation or wheter it's bi-directional. On the Java-side you can have a relation always in both directions due to object references, but on the Database-side, you might only have it in one direction.
Check out JPA Wiki book on that topic for more details.
Additionally, the API doc for OneToOne states:
Specifies a single-valued association to another entity that has
one-to-one multiplicity. It is not normally necessary to specify the
associated target entity explicitly since it can usually be inferred
from the type of the object being referenced. If the relationship is
bidirectional, the non-owning side must use the mappedBy element of
the OneToOne annotation to specify the relationship field or property
of the owning side.

Issues with bidirectional OneToMany mapping and NamedQuery

I have two entities connected bidirectional and I want to query the Location and its votes only for a specific date.
Location:
#Entity
#Table(name = "TAB_LOCATION")
#NamedQueries({
#NamedQuery(name = "Location.getVotedLocations", query = "SELECT l FROM Location l JOIN l.votes v WHERE v.location = l AND DATE(v.createdAt) = DATE(:date) ORDER BY l.name")
})
public class Location extends AbstractEntity {
#Basic
#Size(min = 5, max = 50)
private String name;
#Basic
#Size(min = 0, max = 50)
private String address;
#OneToMany(mappedBy = "location")
private Set<Vote> votes;
#Basic
private String description;
Vote:
#Entity
#Table(name = "TAB_VOTE")
public class Vote extends AbstractEntity {
#Basic
#ManyToOne
#NotNull
private User user;
#Basic
#ManyToOne
#NotNull
private Location location;
I was trying to use the named query but it seems that the Location always contains all votes regardless the condition.
Isn't it possible to map the queried values back to the object?
entityManager.createNamedQuery("Location.getVotedLocations").
setParameter("date", date).getResultList();
What is wrong?
If it isn't possible with NamedQueries, I also can use the Criteria API.
Here's a simple MySql statement that will return locationIDs not Location entity which are voted on a particular date.
Select DISTINCT LocationID FROM VOTE WHERE DATE == dateCreated;
And you can then get the Location entity by LocationID.
When you get an entity as a result from some query, you get the whole entity. It is not possible in JPA to get just a subset of all data, trimmed by where condition.
Well, if you use Hibernate, take a look at Hibernate Filters, with them you could get the result you want.
Note about your query, you have JOIN l.votes so you don't need to join it again with WHERE v.location = l.

JPA Query Many To One nullable relationship

I have the following entities and would like to seek help on how to query for selected attributes from both side of the relationship. Here is my model. Assume all tables are properly created in the db. JPA provider I am using is Hibernate.
#Entity
public class Book{
#Id
private long id;
#Column(nullable = false)
private String ISBNCode;
#ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY, optional = false)
private Person<Author> author;
#ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY, optional = true)
private Person<Borrower> borrower;
}
#Inheritance
#DiscriminatorColumn(name = "personType")
public abstract class Person<T>{
#Id
private long id;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Info information;
}
#Entity
#DiscriminatorValue(PersonType.Author)
public class Author extends Person<Author> {
private long copiesSold;
}
#Entity
#DiscriminatorValue(PersonType.Borrower)
public class Borrower extends Person<Borrower> {
.....
}
#Entity
public class Info {
#Id
private long id;
#Column(nullable=false)
private String firstName;
#Column(nullable=false)
private String lastName;
......;
}
As you can see, the book table has a many to one relation to Person that is not nullable and Person that is nullable.
I have a requirement to show, the following in a tabular format -
ISBNCode - First Name - Last Name - Person Type
How can I write a JPA query that will allow me to select only attributes that I would want. I would want to get the attributes ISBN Code from Book, and then first and last names from the Info object that is related to Person Object that in turn is related to the Book object. I would not want to get all information from Info object, interested only selected information e.g first and last name in this case.
Please note that the relation between the Borrower and Book is marked with optional=true, meaning there may be a book that may not have been yet borrowed by someone (obviously it has an author).
Example to search for books by the author "Marc":
Criteria JPA Standard
CriteriaQuery<Book> criteria = builder.createQuery( Book.class );
Root<Book> personRoot = criteria.from( Book.class );
Predicate predicate = builder.conjunction();
List<Expression<Boolean>> expressions = predicate.getExpressions();
Path<Object> firtsName = personRoot.get("author").get("information").get("firstName");
expressions.add(builder.equal(firtsName, "Marc"));
criteria.where( predicate );
criteria.select(personRoot);
List<Book> books = em.createQuery( criteria ).getResultList();
Criteria JPA Hibernate
List<Book> books = (List<Book>)sess.createCriteria(Book.class).add( Restrictions.eq("author.information.firstName", "Marc") ).list();
We recommend using hibernate criterias for convenience and possibilities.
Regards,