Recursive JPA entity relationship with another composed entity - jpa-2.0

I have these 2 entities called Owner and Folder.
Every folder(s) belong to an owner.
Inside a folder, we can have subfolder(s), and so on.
Owner Entity
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "FOLDER_ID", nullable = false)
private Set<Folder> folders = new HashSet<>();
#Column(nullable = false)
private String name;
// Getters and setters
Folder Entity
#ManyToOne
#JoinColumn(name = "PARENT_FOLDER_ID")
private Folder parent;
#OneToMany(cascade = {CascadeType.ALL}, mappedBy = "parent")
private Set<Folder> children = new HashSet<>(); // recursive
#Column(nullable = false)
private String name;
// Getters and setter
An owner named Steve has a folder called mainFolder with a subFolder inside.
When trying to persist the owner, I hit backref issue.
I believe this is due to the subfolder does not know who is its owner.
Question is, since subFolder is inside a mainFolder and mainFolder belongs to Steve, that makes subFolder belongs to Steve as well.
What JPA relationship can I use for this issue?
public static void main(String[] args) {
Folder mainFolder = new Folder();
Folder subFolder = new Folder();
mainFolder.setName("Main Folder");
mainFolder.getChildren().add(subFolder);
subFolder.setName("SubFolder");
subFolder.setParent(mainFolder);
Owner owner = new Owner();
owner.setName("Steve");
owner.getFolders().add(mainFolder);
em.getTransaction().begin();
em.persist(owner); // backrefs error when trying to persist
em.getTransaction().commit();
}
Exception log
Caused by: org.hibernate.PropertyValueException: not-null property references a null or transient value: entity.Folder._foldersBackref
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:72)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:290)
I am using hibernate with H2.

Related

Problem with updating only some fields of entities in Google Cloud Datastore

I created an entity in Google Cloud Datastore using Python this way:
client = datastore.Client()
key = client.key('EntityType', id)
entity = datastore.Entity(key=key)
entity.update({'id': id, 'property_0': value_0, 'property_1': value_1,})
After this, when I check my entities list, I have a new entity with the 3 properties id, property_0 and property_1
In another function, I only updated property_2 which I do so this way
key = client.key('EntityType', id)
entity = datastore.Entity(key=key)
entity.update({'property_1': new_value_1,})
When I check the entities list after this, I only see property_2 of my entity with the new value.
How can I update only property_1 of the entity while still keeping the other ones?
If you just want to update some properties of your entity, you should not use the .update() method, this method removes properties that you do not assign any value. Instead you could manually set the value for the property you want to change, like in the example below:
# We first create the entity with the properties we want by using the update method.
client = datastore.Client()
key = client.key('EntityType', id)
entity = datastore.Entity(key=key)
entity.update({'property_0': 'a_string_value', 'property_1': 123})
client.put(entity)
# Then later we just fetch that entity and change the property we want.
client = datastore.Client()
key = client.key('EntityType', id)
entity = datastore.Entity(key=key)
entity['property_0'] = 'a_different_string_value'
client.put(entity)
You need to fetch it first
key = client.key('EntityType', id)
entity = client.get(key)
entity.update({'property_2': new_value_2,})

Using JPA metamodel for #OneToMany mappedBy

Could someone explain what is wrong with this and is there a workaround?
private static final String parentField = AbstractType_.parent.getName();
#OneToMany(fetch = FetchType.EAGER, orphanRemoval = true, mappedBy = parentField)
private List<AbstractType> children = new ArrayList<AbstractType>();
In eclipse, this shows and error on the #OneToMany line:
While this would be fine:
The value for annotation attribute OneToMany.mappedBy must be a constant expression.
Also the Maven build fails because of this.
Then again, this will work fine.
private static final String test = "";
#OneToMany(fetch = FetchType.EAGER, orphanRemoval = true, mappedBy = test)
private List<AbstractType> children = new ArrayList<AbstractType>();
UPDATE:
What is happening here, that I wish to get the field name via metamodel, but one can not refer to it at 'mappedBy' attribute.

JPA - How to avoid getting an empty list?

I'm creating a sort of a social networking site, like Facebook, as a university project. Users can upload photos, but I'm somehow unable to retrieve the list of photos for a particular user.
Here's how I'm doing it right now:
#Entity
#Table(name = "users")
public class User implements Serializable {
#Id
private String emailAddress;
private String password;
private String firstName;
private String lastName;
(...)
#OneToMany(mappedBy = "owner", fetch = FetchType.EAGER)
private List<Photo> photos;
public User() {
}
(...)
public void addPhoto( Photo photo){
photos.add(photo);
}
public List<Photo> getPhotos() {
return photos;
}
}
And here's the Photo entity:
#Entity
public class Photo implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String url;
private String label;
#ManyToOne
private User owner;
public Photo() {
}
(...)
public User getOwner() {
return owner;
}
}
Each photo is uploaded by creating a post that contains it. Here's the EJB that does it:
#Stateless
public class PublicPost implements PublicPostRemote {
#PersistenceContext
EntityManager em;
#Override
public void createPost(LoginUserRemote loginUserBean, String targetEmail, final String content, final String photoURL) {
if (loginUserBean.isLoggedIn()) {
final User author = loginUserBean.getLoggedUser();
System.out.println(targetEmail);
final User target = em.find(User.class, targetEmail);
if (author != null && target != null) {
//See if there's a photo to post as well
Photo photo = null;
if (photoURL != null) {
photo = new Photo(photoURL, author, content);
em.persist(photo);
}
MessageBoard publicMessageBoard = target.getPublicMessageBoard();
Post post = new Post(author, content);
post.setMessageBoard(publicMessageBoard);
if (photo != null) {
post.setPostPhoto(photo);
}
em.persist(post);
em.refresh(publicMessageBoard);
//Send an e-mail to the target (if the author and the target are different)
if (!author.getEmailAddress().equals(target.getEmailAddress())) {
final String subject = "[PhaseBook] " + author.getEmailAddress() + " has posted on your public message board.";
Thread mailThread = new Thread() {
#Override
public void run() {
try {
GMailSender.sendMessage(target.getEmailAddress(), subject, content);
} catch (MessagingException ex) {
Logger.getLogger(PublicPost.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
mailThread.start();
}
}
}
}
}
So what happens is: I create a new post that contains a photo, yet later, when I use this, on the web tier...
LoginUserRemote lur = (LoginUserRemote)session.getAttribute("loginUserBean");
User user = lur.getLoggedUser();
List<Photo> photos = user.getPhotos();
System.out.println();
System.out.println("This user has this many photos: " + photos.size());
...it always tells me that the user has 0 photos. Why is this? Am I defining the relationship between user and photo incorrectly? Am I forgetting to persist/refresh anything? Or does the problem lie somewhere else?
If you store a detached User object (the logged in user) in the HTTP session, and then create and persists photos having this detached user as owner, JPA won't automatically add the photo to the detached user. For the entity manager, this detached user doesn't exist: it's not under its responsibility anymore.
Even if User was still attached, it's your responsibility to maintain the coherence of the object graph. If you modify one side of the association (by setting the user as owner of the photo), you should also modify the other side (by adding the photo to the list of photos of the owner).
I'm not absolutely sure this is the cause of the problem, because you haven't shown us what the loginUserBean was and did to get the logged in user, but it might be the answer.
There is a series of issues here:
Are photos actually stored in the database? Maybe you don't have a transaction open?
You are not updating both sides of the association.
Theoretically you only need to update the owning side, but better be safe than sorry:
photo = new Photo(photoURL, author, content);
em.persist(photo);
author.addPhoto(photo);
You are fetching the user from a session and then retrieving associated collection of photos. Do you really know what this means? If the user has hundreds of photos, do you really want to store them in HTTP session along with the user all the time? This is not how Facebook works ;-).
I think refreshing your entity (with em.refresh(lur.getLoggedUser())) might work, but only at university, not in real life. Loading all the user photos at once into memory is an overkill. Personally I would even remove photos association from user to avoid this. Load one page at a time and only on demand.
Even if you know what you are doing or such a behaviour is acceptable, objects stored in HTTP session are so called detached from persistence context, meaning your persistence provider does no longer keep track of them. So adding a photo does not mean that the photos collection will be magically updated in every object. I think about carefully, this would be even worse.
Last but not least, your createPost() really needs some code review. It does at least 4 things at once, System.out, one time threads created on demand, silently doing nothing when preconditions are not met (like user not being logged in, missing parameters), mixing concerns on different level of abstraction. Don't want to be too meticulous, but your grade might be influenced by the quality of code.

What's the lazy strategy and how does it work?

I have a problem. I'm learning JPA. I'm using embedded OpenEJB container in unit tests, but only working is #OneToMany(fetch=EAGER). Otherwise is the collection allways null. I haven't found, how the lazy strategy works, how the container fills the data and in which circumstances triggers the container the loading action?
I have read, that the action triggers when the getter is being called. But when I have the code:
#OneToMany(fetch = LAZY, mappedBy="someField")
private Set<AnotherEntities> entities = new Set<AnotherEntities>();
...
public Set<AnotherEntities> getEntities() {
return entities;
}
I'm always getting null. I thing, the LAZY strategy cannot be tested with embedded container. The problem might be also in the bidirectional relation.
Does have anybody else similar expiriences with the JPA testing?
Attachments
The real test case with setup:
#RunWith(UnitilsJUnit4TestClassRunner.class)
#DataSet("dataSource.xml")
public class UnitilsCheck extends UnitilsJUnit4 {
private Persister prs;
public UnitilsCheck() {
Throwable err = null;
try {
Class.forName("org.hsqldb.jdbcDriver").newInstance();
Properties props = new Properties();
props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.LocalInitialContextFactory");
props.put("ds", "new://Resource?type=DataSource");
props.put("ds.JdbcDriver", "org.hsqldb.jdbcDriver");
props.put("ds.JdbcUrl", "jdbc:hsqldb:mem:PhoneBookDB");
props.put("ds.UserName", "sa");
props.put("ds.Password", "");
props.put("ds.JtaManaged", "true");
Context context = new InitialContext(props);
prs = (Persister) context.lookup("PersisterImplRemote");
}
catch (Throwable e) {
e.printStackTrace();
err = e;
}
TestCase.assertNull(err);
}
#Test
public void obtainNickNamesLazily() {
TestCase.assertNotNull(prs);
PersistableObject po = prs.findByPrimaryKey("Ferenc");
TestCase.assertNotNull(po);
Collection<NickNames> nicks = po.getNickNames();
TestCase.assertNotNull(nicks);
TestCase.assertEquals("[Nick name: Kutyafája, belongs to Ferenc]", nicks.toString());
}
}
The bean Presister is the bean mediating access to the entity beans. The crucial code of class follows:
#PersistenceUnit(unitName="PhonePU")
protected EntityManagerFactory emf;
public PhoneBook findByPrimaryKey(String name) {
EntityManager em = emf.createEntityManager();
PhoneBook phonebook = (PhoneBook)em.find(PhoneBook.class, name);
em.close();
return phonebook;
}
Entity PhoneBook is one line of phone book (also person). One person can have zero or more nick names. With EAGER strategy it works. With LAZY the collection is allways null. May be the problem is in the detaching of objects. (See OpenEJB - JPA Concepts, part Caches and detaching.) But in the manual is written, that the collection can be sometimes (more like manytimes) empty, but not null.
The problem is in the life cycle of an entity. (Geronimo uses OpenJPA, so le't see OpenJPA tutorial, part Entity Lifecycle Management.) The application uses container managed transactions. Each method call on the bean Persiser runs in an own transation. And the persistency context depends on the transaction. The entity is disconnected from its context at the end of the transaction, thus at the end of the method. I tried to get the entity and on second line in the same method to get the collection of nick names and it worked. So the problem was identifyed: I cannot get additionally any entity data from the data store without re-attaching the entity to some persistency context. The entity is re-attached by the EntityManager.merge() method.
The code needs more correctures. Because the entity cannot obtain the EntityManager reference and re-attach itself, the method returning nick names must be moved to the Persister class. (The comment Heureka marks the critical line re-attaching the entity.)
public Collection<NickNames> getNickNamesFor(PhoneBook pb) {
//emf is an EntityManagerFactory reference
EntityManager em = emf.createEntityManager();
PhoneBook pb = em.merge(pb); //Heureka!
Collection<NickNames> nicks = pb.getNickNames();
em.close();
return nicks;
}
The collection is then obtained in this way:
//I have a PhoneBook instance pb
//pb.getNickNames() returns null only
//I have a Persister instance pe
nicks = pe.getNickNames(pb);
That's all.
You can have a look at my second question concerning this topic I'have asked on this forum. It is the qustion OpenJPA - lazy fetching does not work.
How I would write the code
#Entity
public class MyEntity {
#OneToMany(fetch = LAZY, mappedBy="someField")
private Set<AnotherEntities> entities;
// Constructor for JPA
// Fields aren't initalized here so that each em.load
// won't create unnecessary objects
private MyEntity() {}
// Factory method for the rest
// Have field initialization with default values here
public static MyEntity create() {
MyEntity e = new MyEntity();
e.entities = new Set<AnotherEntities>();
return e;
}
public Set<AnotherEntities> getEntities() {
return entities;
}
}
Idea no 2:
I just thought that the order of operations in EAGER and LAZY fetching may differ i.e. EAGER fetching may
Declare field entities
Fetch value for entities (I'd assume null)
Set value of entities to new Set<T>()
while LAZY may
Declare field `entities
set value of entities to new Set<T>()
Fetch value for entities (I'd assume null)'
Have to find a citation for this as well.
Idea no 1: (Not the right answer)
What if you'd annotate the getter instead of the field? This should instruct JPA to use getters and setters instead of field access.
In the Java Persistence API, an entity can have field-based or
property-based access. In field-based access, the persistence provider
accesses the state of the entity directly through its instance
variables. In property-based access, the persistence provider uses
JavaBeans-style get/set accessor methods to access the entity's
persistent properties.
From The Java Persistence API - A Simpler Programming Model for Entity Persistence

How do I update with a newly-created detached entity using NHibernate?

Explanation:
Let's say I have an object graph that's nested several levels deep and each entity has a bi-directional relationship with each other.
A -> B -> C -> D -> E
Or in other words, A has a collection of B and B has a reference back to A, and B has a collection of C and C has a reference back to B, etc...
Now let's say I want to edit some data for an instance ofC. In Winforms, I would use something like this:
var instanceOfC;
using (var session = SessionFactory.OpenSession())
{
// get the instance of C with Id = 3
instanceOfC = session.Linq<C>().Where(x => x.Id == 3);
}
SendToUIAndLetUserUpdateData(instanceOfC);
using (var session = SessionFactory.OpenSession())
{
// re-attach the detached entity and update it
session.Update(instanceOfC);
}
In plain English, we grab a persistent instance out of the database, detach it, give it to the UI layer for editing, then re-attach it and save it back to the database.
Problem:
This works fine for Winform applications because we're using the same entity all throughout, the only difference being that it goes from persistent to detached to persistent again.
The problem is that now I'm using a web service and a browser, sending over JSON data. The entity gets serialized into a string, and de-serialized into a new entity. It's no longer a detached entity, but rather a transient one that just happens to have the same ID as the persistent one (and updated fields). If I use this entity to update, it will wipe out the relationship to B and D because they don't exist in this new transient entity.
Question:
My question is, how do I serialize detached entities over the web to a client, receive them back, and save them, while preserving any relationships that I didn't explicitly change? I know about ISession.SaveOrUpdateCopy and ISession.Merge() (they seem to do the same thing?), but this will still wipe out the relationships if I don't explicitly set them. I could copy the fields from the transient entity to the persistent entity one by one, but this doesn't work too well when it comes to relationships and I'd have to handle version comparisons manually.
I solved this problem by using an intermediate class to hold data coming in from the web service, then copying its properties to the database entity. For example, let's say I have two entities like so:
Entity Classes
public class Album
{
public virtual int Id { get; set; }
public virtual ICollection Photos { get; set; }
}
public class Photo
{
public virtual int Id { get; set; }
public virtual Album Album { get; set; }
public virtual string Name { get; set; }
public virtual string PathToFile { get; set; }
}
Album contains a collection of Photo objects, and Photo has a reference back to the Album it's in, so it's a bidirectional relationship. I then create a PhotoDTO class:
DTO Class
public class PhotoDTO
{
public virtual int Id { get; set; }
public virtual int AlbumId { get; set; }
public virtual string Name { get; set; }
// note that the DTO does not have a PathToFile property
}
Now let's say I have the following Photo stored in the database:
Server Data
new Photo
{
Id = 15,
Name = "Fluffy Kittens",
Album = Session.Load<Album>(3)
};
The client now wants to update the photo's name. They send over the following JSON to the server:
Client Data
PUT http://server/photos/15
{
"id": 15,
"albumid": 3,
"name": "Angry Kittens"
}
The server then deserializes the JSON into a PhotoDTO object. On the server side, we update the Photo like this:
Server Code
var photoDTO = DeserializeJson();
var photoDB = Session.Load(photoDTO.Id); // or use the ID in the URL
// copy the properties from photoDTO to photoDB
photoDB.Name = photoDTO.Name;
photoDB.Album = Session.Load<Album>(photoDTO.AlbumId);
Session.Flush(); // save the changes to the DB
Explanation
This was the best solution I've found because:
You can choose which properties the client is allowed to modify. For example, PhotoDTO doesn't have a PathToFile property, so the client can never modify it.
You can also choose whether to update a property or not. For example, if the client didn't send over an AlbumId, it will be 0. You can check for that and not change the Album if the ID is 0. Likewise, if the user doesn't send over a Name, you can choose not to update that property.
You don't have to worry about the lifecycle of an entity because it will always be retrieved and updated within the scope of a single session.
AutoMapper
I recommend using AutoMapper to automatically copy the properties from the DTO to the entity, especially if your entites have a lot of properties. It saves you the trouble of having to write every property by hand, and has a lot of configurability.