I have a java object that I have persisted using JPA. This object has a member 'friendsList' that is a list of strings. I have used the #CollectionOfElements hibernate annotation on this object. The result of this is that I have two tables, one that persists my object, and another that persists the lists of each of these objects.
How can I retrieve (using jpa) all objects whose lists contain 'hello' or 'world' ?
Following is working fine : it will also create a Parent_names table for maintaining relationships. Don't annotate with #OneToMany
#ElementCollection(targetClass = String.class)
private List<String> names;
Or I think you can try a workaround :
Wrap string inside a class.
class FriendsName{
private String name;
//getter setter
}
Then,
class Parent{
#OneToMany
List<FriendsName> friendsName;
}
And you can do JPQL like:
select p from Parent p where p.friendsName.name in ('hello','world')
Related
I have a path object in java created by querydsl.
This is the result of toString method: lote.edificacoes.id
lote is the object
edificacoes is the list inside the object
id is the attribute that i'd like to do the operation
When i use path.gt(100) for example, i'm getting the following error: illegal attempt to dereference collection
It's not possible do a join cause i just have the path object because this object is created by a reflection.
This a example from my code
Lote class
#Entity
public class Lote {
#OneToMany(mappedBy = "lote", fetch = FetchType.EAGER)
private List<Edificacao> edificacoes;
//getter and setter
}
path.gt(100);
I expected the output of the list of results, a list of Lote
Well, according to the documentation this is not possible.
http://lists.jboss.org/pipermail/hibernate-issues/2007-July/006157.html
Let's say i have a association as ,
class Department{
......
#OneToMany(fetch = FetchType.LAZY)
private List<Employee> employees;
}
Now when i fetch Department, will it fetch anything in employees list or will it be completely empty.
Will identifiers for employee object be loaded in list like say i have employee object attributes as below:-
Employee{
id
name
doj
....
}
Lazy object like {
id -> 111
name -> null
doj -> null
}
Now when i initialize employee object or access it's properties using getters, then the object will be loaded from database using id as an identifier...??
Instead of the real collection class (e.g. ArrayList) a different List implementation is injected into your field (PersistentList). Depending on the calls on that collection and the lazy strategy it will do different things:
In case lazy="lazy" the call to any of the collections methods would get the collection fully loaded
If lazy="extra", then calls to some functions would trigger SQL without loading the collection. E.g. list.size() would trigger select count.... While getting the 1st element would select only that element. This may be suitable for large collections. Note, that this behaviour may also depend on the collection type - unordered collections will load all elements anyway.
Lazy fetch type, Hibernate won’t load the relationships for that particular object instance.
FetchType.LAZY = Doesn’t load the relationships unless explicitly “asked for” via getters
FetchType.EAGER = Loads ALL relationships
In your case It won't load Employee List from database unless you explicitly fire query for it, Because you have set fetch type ( fetch = FetchType.LAZY ). If fetch type was ( fetch = FetchType.EAGER ) then It would explicitly fire a select query for Employee list. In that object you would get all employee property eg name, doj.
the object will be loaded from database using id as an identifier...??
Department{
#OneToMany(fetch = FetchType.EAGER,,mappedBy = "department")
private List<Employee> employees;
}
In Emplooyee.... You need to mapped it by reference of department object.
eg:
Employee{
// Reference of department.
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "departmentid", nullable = false)
private Department department;
}
This way it will become bidirectional. now Hibernate will fire query by reference (id in native sql) .
If you want to be loaded lazily the set Fetch mode FetchType.LAZY in both mapping....
In your case until you explicitly access Department.employees (through a getter or any other means) It will not load the Employee entities. There will be a Proxy for this. It will be initialized once at the first call to access this employees collection.
How Lazy Loading Works in Hibernate
The simplest way that Hibernate can apply lazy load behavior upon your entities and associations is by providing a proxy implementation of them. Hibernate intercepts calls to the entity by substituting a proxy for it derived from the entity’s class. Where the requested information is missing, it will be loaded from the database before control is ceded to the parent entity’s implementation.
Please note that when the association is represented as a collection class, then a wrapper (essentially a proxy for the collection, rather than for the entities that it contains) is created and substituted for the original collection. When you access this collection proxy then what you get inside returned proxy collection are not proxy entities; rather they are actual entities. You need not to put much pressure on understanding this concept because on runtime it hardly matters.
Please refer this for more information:
http://howtodoinjava.com/hibernate/lazy-loading-in-hibernate/
Also enable hibernate.sql.show=true so that you can see what queries are being fired when you are trying to fetch the collections.
I have an entity with two Embedded classes of the same type and which one has an ElementCollection of the same type two. The business logic is apparently correct, but I am experiencing some problems with lack of knowledge in JPA, I guess.
Let's check my classes:
#Entity
public class Etapa extends EntidadeBase {
#Embedded
private CronogramaDeDesembolso cronogramaDeReceita;
#Embedded
private CronogramaDeDesembolso cronogramaDeDespesa;
}
#Embeddable
public class CronogramaDeDesembolso {
#ElementCollection
private List<Parcela> parcelas;
}
I am receiving the following error log.
Caused by: org.hibernate.HibernateException: Found shared references
to a collection:
nexxus.convenioestadual.dominio.planodetrabalho.etapa.Etapa.cronogramaDeReceita.parcelas
Do you guys have any clue of what is wrong and how can I fix it?
EDIT:
Due comments I did this edit and it do not worked too
#Entity
public class Etapa extends EntidadeBase {
#Embedded
#AttributeOverride(name = "parcelas", column = #Column(name = "parcelasReceita"))
private CronogramaDeDesembolso cronogramaDeReceita;
#Embedded
#AttributeOverride(name = "parcelas", column = #Column(name = "parcelasDespesa"))
private CronogramaDeDesembolso cronogramaDeDespesa;
}
Is there any reason why you have decided to use this structure ? Typically when converting an object to an RDBMS you would need to model the relationships. When you use an embeddable it will add the column (or columns) associated with it to the table. So when you do this normally (not collections) it is fine.
When you do a collection it runs into issues. Mainly there is no way to represent a collection in a single row (since this is an entity you could have many of them so effectively for each object you only have one row) & one column. So when you represent a collection you actually have to have a second table with a column referencing it back to the first. It's really the opposite thinking of a normal object. The collection entries need to know what collection they were associated with instead of the collection being knowledgeable of its entries.
So in some POJO you could have and these....
MyListObject {
//Some implementation of things you want to collect
}
MyClass {
List<MyListObject> myListObject;
}
But to model this in JPA you would need to have these represented by two tables.
Your object that will be in the list.
#Entity
MyListObject {
#ManyToOne
#JoinColumn(name = "MY_CLASS_KEY")
private MyClass myClass;
}
Your object/entity that will have the list.
#Entity
MyClass {
#Id
#Column(name = "MY_CLASS_KEY")
private Long myClassKey;
#OneToMany(mappedBy = "myClass")
private List<MyListObject> myString;
}
I hope this helps.
A quick search on Google turned up this in StackOverflow:
JPA Multiple Embedded fields
It would seem as though you have to do some explicit annotation overriding over the fields within the embeddable class. There are some code examples in the linked answer as well that should give you a good idea of where to go.
Cheers,
Let's say I have a Person JPA entity:
#Entity
public class Person {
#Id
private Long id;
#Column(name="name")
private String name;
#Column(name="age")
private Integer age;
#Column(name="hobbies")
private List<String> hobbies;
public Person() {};
}
Using a Criteria Query, is it possible to retrieve a List<Person>, but only include each Person's name?
Looking at Java Persistence with Hibernate, I see that there's a Criteria#setResultTransformer method.
I think that I could transform my results to a ReducedPerson class that only contained a name. However, I'd like to select only the Person's name, but still get Person objects back.
Is this possible?
You're correct, you'll need to set a ResultTransformer. For what I know in this area of hibernate, which is not much, the transformers provided by Hibernate are strict and will fail if a value is missing, so I think you'll need to create your own instance of ResultTransformer. I would suggest to look at the code from AliasToBeanResultTransformer and make a lenient version of it.
You can do this using Constructor Expressions:
http://en.wikibooks.org/wiki/Java_Persistence/JPQL#Constructors
You can use your existing Person class (instances returned from your query being, of course, unmanaged) but would however need to a constructor taking the name.
SELECT NEW sample.Person(p.name) FROM Person p
Single Projection
You use an existing ResultTransformer like this
Criteria query = session.createCriteria(Person.class)
.setProjection(Projections.property("name").as("name"))
.setResultTransformer(Transformers.aliasToBean(Person.class));
List personNames = query.list();
Multiple Projections
The example List above now contains only Person objects with their name. Regullary, you want also to retrieve the id for the persons at least. You can setup multiple properties with this
ProjectionList colProjection = Projections.projectionList();
colProjection.add(Projections.property("id"), "id");
colProjection.add(Projections.property("name"), "name");
Criteria query = session.CreateCriteria(Person.class)
.setProjection(colProjection)
.setResultTransformer(Transformers.aliasToBean(Person.class));
List persons = query.list();
Key in this approach is to set the same aliases as their original property names, so we dont need to build our own ResultTransformer.
I am getting an exception
object references an unsaved transient instance - save the transient instance before flushing
thrown in the following code:
public void addThing(String key, String someData) {
Thing thing = new Thing();
booking.setData(someData);
booking.setParent(this);
bookings.put(key, thing);
}
The Parent mapping is:
#ElementCollection(fetch=FetchType.EAGER)
#Column(name="thing", nullable=false)
#MapKeyColumn(name="key")
#JoinColumn(name="parent_id")
protected Map<String, Thing> things = Maps.newHashMap();
The child ('Thing') mapping is:
#ManyToOne
private Parent parent;
According to the Hibernate manual:
There is no cascade option on an ElementCollection, the target objects are always persisted, merged, removed with their parent.
But - before I changed to the new #ElementCollection mapping so solve a problem where I was getting apparently phantom elements returned for a query, this code worked correctly.
I know I can save the element separately and then make a reference, but I prefer to have it done automatically, and I thought that was the way it is supposed to work. Any ideas?
#ElementCollection is not supposed to be used with collections of entities; it's used with collections of #Embeddable. If Thing is an entity, you don't use #ElementCollection, you use #OneToMany.
From the javadoc for #ElementCollection:
Defines a collection of instances of a basic type or embeddable class