I have a parent entity that has child entities (A) who in turn have their own child entities (B).
#Entity
public class Parent {
#OneToMany
Set<ChildA> childrenA;
}
#Entity
public class ChildA {
#OneToMany
Set<ChildB> childrenB;
}
I'm trying to display the data via a JSF dataTable. I would like to show the following.
Parent1 | NumberOfRelatedChildrenB
Parent2 | NumberOfRelatedChildrenB
To generate the rows in the dataTable I'm using a MangagedBean which gets a List of the Parents via a ParentFacade.findAll(), but I can't figure out how I can get a List of all the associated ChildBs. I guess I could add a #OneToMany ChildB relationship to the Parent entity, but I was hoping there would be a way to get them via the ChildA relationship?
Thanks in advance & sorry for the poor explanation!
No, I suggest to avoid creating an additional relationship in this case. One way is to create a method in the managed bean that returns the number of related ChildB given an input Parent:
#ManagedBean
public class MyManagedBean {
private List<Parent> parentList;//+getter
private Map<Long, Long> relatedChildrenB = new HashMap<Long,Long>();//+getter
#EJB
private ParentFacade parentFacade;
#PostConstruct
public void init() {
parentList = parentFacade.findAll();
for (Parent parent : parentList) {
relatedChildrenB.put(parent.getId(), parentFacade.getNumberOfRelatedChildrenB(parent));
}
}
and in the facelets page:
<h:dataTable value="#{myManagedBean.parentList}" var="parent">
...
#{myManagedBean.relatedChildrenB[parent.id]}
</h:dataTable>
and implement the corresponding queries in the facade service class.
Note that passing an object using parenthesis () in the previous revision in an EL expression requires EL 2.2 and thus either a Servlet 3.0 compatible container or applying some workaround. This solution does not need method call with parameters.
Finally, note that in my final edit I have followed the wise suggestion of skuntsel to avoid db calls in getter methods.
Simple solution would be to put a method in Parent that returns children count and then use it in dataTable column e.g.
#Transient
public int getAllChildrenCount() {
// iterate through children list and count
}
On view:
#{parent.allChildrenCount}
Related
I have several polymorphic JPA entities, and I'm curious as to whether it's possible to do Polymorphic selects when using an #Query tag.
I've got some entities in roughly the following relationship:
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public class ParentObject {
//common fields - it's CRM-like
}
#Entity
public class ChildObject extends ParentObject {
//specific fields - a particular kind of case
}
#Entity
public class ChildObjectPartDeux extends ParentObject {
//specific fields - another kind of case
}
I've then got a parent repository, something like:
#Repository
public interface IParentObjectRepository <T extends ParentObject> extends JpaRepository<T, Long> {
Page<T> findAllByCommonField(Pageable page);
#Query("SELECT p FROM ParentObject p WHERE someFiddlyConditionWhichNeedsAQueryTag")
Page<T> aFiddlyQuery(Pageable page, Object someParameter);
}
The first definition works a treat, and other repositories which inherit from the ParentObject and associated repository work needn't provide their own ChildObject-specific version - they only return ChildObjects.
The second definition works as long as only one kind of child is present in the system, after which point everything goes south. My (potentially flawed) understanding is that as I am explicitly selecting from ParentObject in the #Query, this query also runs "as-is" when it's inherited, and there isn't a handler to cast ChildObjectPartDeux to ChildObject. Not that I'd want to do that, anyway.
Right now, I'm getting round this issue by overriding these #Query-tagged methods in the child repository and swapping out the object name, as shown below, but it feels like there should be a DRY-er way to do this:
#Repository
public interface IChildObjectRepository extends IParentObjectRepository<ChildObject> {
#Query("SELECT c FROM ChildObject c WHERE someFiddlyConditionWhichNeedsAQueryTag")
Page<ChildObject> aFiddlyQuery(Pageable page, Object someParameter);
}
The behaviour I'd hope for is similar to the first method, that the JpaRepository<TypeInHere, Long> dictates which kinds of item are due to be returned and inform which items should be selected. Is there a way to feed that into a #Query tag?
I have the following structure :
#MappedSuperclass
public abstract class Action {
...
}
And than few entities extending Action, for example :
#Entity(name="chemistry")
public class Chemistry extends Action implements Serializable {
...
}
In order to execute the persistance I used JPARepository :
#NoRepositoryBean
public interface ActionRepository<T extends Action> extends JpaRepository<T, String> {
...
}
And an interface for the children :
#Component
#Service
#Repository
interface ChemistryRepository extends ActionRepository<Chemistry> {
}
The persistance mechanism works fine for all the entities inheriting from Action.
Now I have a problem.
I have another table in the DB, called 'action_params', including additional key-value parameters which related to a specific action (i.e. chemistry).
I have the appropriate entity :
#Entity(name="action_params")
public class ActionParams implements Serializable {
...
}
In the DB I cannot use foreign key since the key is not related to a specific table but any table inherits from Action. this is ok, I would like to use a query in order to get for each Action the records from the table action_params, based on its id.
And I would like to add a List to Action, mapping those records as a list. I tried using hibernate but any query returns empty (The following code was added into Action class):
#OneToMany
#JoinFormula(value="select p from action_params p where p.action_id = id")
#Transient
protected List<ActionParams> actionParamsList;
This is not working. I also tried to autowire the ActionParamsRepository into Action, but of course there is no way doing it and I could not think of any other way.
Your advice will be much appreciated
What strong reason you have to use a JPA relation?
If there is no such reason, I'd suggest you to implement a new finder method in the ActionParams repository. Something like this:
#Query("select p from action_params p where p.action_id = :actionId")
List<ActionParams> findAllByActionId(#Param("actionId") Long actionId )
I suppose the type is Long. Replace it if you have other type.
You can use #Formula, so let me explain, when you put a query on the formula, in Hibernate is added a subquery.
#Formula("(SELECT p FROM action_params p WHERE p.action_id = id)")
private List<ActionParams> actionParamsList;
I've got a pretty straight-forward problem I think but I couldn't come up with a nice structure for the classes with Hibernate or find examples of best practices.
I've got one table test with a mapped class Test. On one page controlled by a bean I've got all the items in a list for administrative editing (AdminTest) and in another page the same items are listed but for normal users with things like radio-buttons to influence them (ShowTest) without altering the database.
Since Hibernate seem to insist that you specify a directly mapped class when you retrieve items with the addEntity-function (in my classes ending with Manager) it feels like I'm forced to do something like this:
class Test { ... }
class AdminTest extends Test { ... }
#ManagedBean
class AdminTestManager {
List<AdminTest> items;
}
class ShowTest extends Test { ... }
#ManagedBean
class ShowTestManager {
List<ShowTest> items;
}
Then have separate mapping for both AdminTest and ShowTest to the same table with the same fields. This is really bad since I need to update both mappings whenever I add a field to the table test.
It feels like I've missed something here, that you should really just need the one Test mapped to the table test then have some pretty inheritance mapping but those require some identifier like a column or one-to-one mapped table.
EDIT:
Another solution I've tried was having one mapping for Test, still having AdminTest and ShowTest extend that class, but I'm copying the getters with reflection to the extended classes.
EDIT 2:
I'll provide a "real world" scenario here to better explain what I'm asking. Lets say I want to make a quiz-engine with one page where you can fill in questions through input-fields and another which lists these questions with a radio-button by each item with just "yes" or "no".
The database-table would just be created like this:
CREATE TABLE question (id INT AUTO_iNCREMENT, text VARCHAR, correct_answer INT, primary key(id));
The classes that I think I would need are these:
class Question {
private int id;
private String text;
private int correctAnswer;
// Getters and setters.
}
class EditQuestion extends Question {
void updateItem() { ... }
void removeItem() { ... }
}
#ManagedBean(name = "edit_quiz")
#ViewScoped
class EditQuestionManager {
List<EditQuestion> items;
void addItem() { ... }
void init() {
items = (ArrayList<EditQuestion>) HibernateUtil.getSessionFactory().getCurrentSession().createSQLQuery("SELECT * FROM question").addEntity(EditQuestion.class)
.list();
}
}
class AnswerQuestion extends Question {
int radioButtonValue;
// Getters and setters.
}
#ManagedBean(name = "take_quiz")
#ViewScoped
class AnswerQuestionManager {
List<AnswerQuestion> items;
void calculateResults() { ... }
void init() {
items = (ArrayList<AnswerQuestion>) HibernateUtil.getSessionFactory().getCurrentSession().createSQLQuery("SELECT * FROM question").addEntity(AnswerQuestion.class).list();
}
}
Then for example the JSF-page displaying the quiz could be something like this:
<ui:repeat value="#{take_quiz.items}" var="question">
<div>#{question.text}</div>
<h:selectOneRadio value="#{question.radioButtonValue}" onchange="submit()">
<f:selectItem itemValue="1" itemLabel="Yes" />
<f:selectItem itemValue="0" itemLabel="No" />
</h:selectOneRadio>
</ui:repeat>
<h:commandLink action="#{take_quiz.calculateResults()}">Done</h:commandLink>
Now the problem, at-least as it appears to me, is that to make this sort of list for both the admin-view and user-view I need to make entries to map the table "question" to both AnswerQuestion and EditQuestion in the hbm.xml-file. At-least without using reflection (to copy all the getter-values from Question to a new instance of AnswerQuestion/EditQuestion) which sort of feel like a hack to me? I mean this doesn't seem too complicated?
SOLUTION: Instead of having the classes extend the mapped Hibernate-table classes I simply added a private property of their types. Also in the Manager-classes I loop through the items from the database after they've been retrieved and set the lists like this:
ArrayList<Question> tempItems = (ArrayList<Question>) HibernateUtil.getSessionFactory().getCurrentSession().createSQLQuery("SELECT * FROM question").addEntity(Question.class).list();
ArrayList<EditQuestion> items = ArrayList<EditQuestion>();
for(int i = 0; tempItems.size(); i++) {
EditQuestion item = new EditQuestion();
item.setQuestion(tempItems.get(i));
items.add(item);
}
I'm struggling to understand your question. Are you having trouble expressing Class inheritance for entities?
Have you considered using the import javax.persistence.Inheritance annotation on top of your Test class?
Example:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Test {
}
#Entity
public class AdminTest extends Test {
}
More here.
Can any one say to me that can I return Hibernate Entities as return value in JAXWS web service methods!?
Indeed I have some Entities like these:
#Entity
public class Parent {
...
private Childone childoneByChildoneid;
#ManyToOne
public
#javax.persistence.JoinColumn(name="ChildOneId",referencedColumnName="Id")
Childone getChildoneByChildoneid() {
return childoneByChildoneid;
}
public void setChildoneByChildoneid(Childone childoneByChildoneid) {
this.childoneByChildoneid = childoneByChildoneid;
}
...
}
#Entity
public class Childone {
...
private Collection<Parent> parentsById;
#OneToMany(mappedBy = "childoneByChildoneid")
public Collection<Parent> getParentsById() {
return parentsById;
}
public void setParentsById(Collection<Parent> parentsById) {
this.parentsById = parentsById;
}
...
}
And have a service like this:
#Stateless
#WebService()
public class MasterDataService {
#EJB
private MasterDataManager manager;
#WebMethod
public Parent getParent(int parentId) {
return manager.getParent(parentId);
}
}
#Stateless
public class MasterDataManager {
#PersistenceContext
EntityManager em;
public Parent getParent(int parentId) {
Parent parent = (Parent) em.createQuery(
"select p from Parent p where p.id=:parentId")
.setParameter("parentId", parentId).getSingleResult();
return parent;
}
}
When I call this web method from client I get LazyInitializationException exception :(
I test Serializable and Cloneable interfaces and override clone method but unfortunately it doesn't work, I use em.detach(parent) in manager but it doesn't work still.
Can any one help me?
tnax
It is debatable. Generally, you have two options:
return the entities, but make sure they are initialized. Either mark the #*ToMany with fetch=FetchType.EAGER or use Hibernate.initialize(..). The reason for the exception is that by default all collections in entities are not fetched from the database until requested. But when you request them from the jax-ws serializer, the hibernate session is already closed. Technically, you can have some OpenSessionInViewIntercepetor but I don't think there's something ready-to-use with JAX-WS, and it might be a problem to write one. If you don't want to transfer these collections, you can annotate them with #XmlTransient (or #JsonIgnore, depending on the serialization technique). It makes the entity somewhat of a mess, but I still prefer it to code duplication.
Use DTOs (data transfer objects) - transfer all data from the entity to a new object with a similar structure, that will be exposed by the web service. Again you'd have to make sure you are populating the DTO when the hibernate session is active
I prefer the first option, because it requires less biolerplate code, but I agree one should be very careful with entity state management when using it.
I'm working on GAE-based applications, which uses JDO to access datastore. I need to implement polymorphic relationship between persisted objects.
There's abstract parent class:
#PersistenceCapable
#Inheritance(strategy = InheritanceStrategy.SUBCLASS_TABLE)
public abstract class Parent {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
#Extension(vendorName = "datanucleus", key = "gae.encoded-pk", value = "true")
String id;
// ....
And several child classes:
#PersistenceCapable (identityType = IdentityType.APPLICATION)
public class Child extends Parent {
// ....
Also, there's one more class, which should have reference to one of child classes. According to "Polymorphic Relationships" section of "Entity Relationships in JDO" article, the best way to implement such relationship is to store key of an object, so this class looks in the following way:
#PersistenceCapable (identityType = IdentityType.APPLICATION)
public class OtherClass {
#Persistent
private String reference;
// ....
I retrieve string key of referenced object from instance of OtherClass. Then I would like to obtain referenced object itself: it's an instance of one of Parent subclasses. BUT:
If I do it with pm.getObjectById(oid) method:
Object object = pm.getObjectById(reference);
JDOObjectNotFoundException exception is thrown (javax.jdo.JDOObjectNotFoundException: No such object FailedObject:...).
If I do it with getObjectById(class, key) method:
Parent object = pm.getObjectById(Parent.class, reference);
FatalNucleusUserException exception is thrown (org.datanucleus.store.appengine.FatalNucleusUserException: Received a request to find an object of kind Parent but the provided identifier is the String representation of a Key for kind Child)
What is correct way to retrieve instance of one of subclasses referenced in another entity?
UPDATE: I found this thread in GAE google group, but frankly it did not help me a lot.
I found the same problem with JDO and App Engine, so I started a project that implements a workaround for this. https://code.google.com/p/datanucleus-appengine-patch/
My first test with the code I have now looks okay, feel free to try it out at give me some feedback.
Actually my workaround may solve your problem 2 ways.
I implemented a getObjectById(class, id) that also looks for kinds that are instances of the provided class.
I implemented a getObjectById(oid) that does some special handling of lookup if oid is of type com.google.appengine.api.datastore.Key, then it will figure out the correct class to return.
I added a new annotation #PolymorphicRelationship that will make is easy to handle to workaround that App Engine describes, with storing the keys. Sample shown below:
#Persist
public Collection<Key> myChildKeys;
#NotPersistent
#PolymorphicRelationship(keyField ="myChildKeys")
public Collection<TestChild> myChildren;
I'm using this rather cancerous and smelly anti-pattern to get around this limitation of JDO/App Engine.
#JsonIgnore
#Persistent(mappedBy="account")
private List<XProvider> xProviders;
#JsonIgnore
#Persistent(mappedBy="account")
private List<YProvider> yProviders;
// TODO: add extra providers here and in getProviders() below...
And then to get the collection:
public List<XProvider> getXProviders() {
if (xProviders == null) {
xProviders = new ArrayList<XProvider>();
}
return xProviders;
}
//etc with other getters and setters for each collection.
public List<Provider> getProviders() {
List<Provider> allProviders = new ArrayList<Provider>();
// TODO: add extra providers here...
allProviders.addAll(getXProviders());
allProviders.addAll(getYProviders());
return allProviders;
}
It's a bad solution, but any port in a storm...
(Also relates a little to this bug, using interfaces as the collection type http://code.google.com/p/datanucleus-appengine/issues/detail?id=207)
App Engine's JDO layer doesn't currently support polymorphism. In fact, I'm not sure if JDO supports it in general or not.