Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA: How do I avoid loading an object simply so I can store its ID in the database?

This question is so simple, you can probably just read the code

This is a very simple performance question. In the code example below, I wish to set the Owner on my Cat object. I have the ownerId, but the cats method for requires an Owner object, not a Long. Eg: setOwner(Owner owner)

@Autowired OwnerRepository ownerRepository;
@Autowired CatRepository catRepository;

Long ownerId = 21;
Cat cat = new Cat("Jake");
cat.setOwner(ownerRepository.findById(ownerId)); // What a waste of time
catRepository.save(cat)

I'm using the ownerId to load an Owner object, so I can call the setter on the Cat which is simply going to pull out the id, and save the Cat record with an owner_id. So essentially I'm loading an owner for nothing.

What is the correct pattern for this?

like image 228
sparkyspider Avatar asked Nov 05 '15 15:11

sparkyspider


People also ask

Which method of JPA implementation saves an object into database?

You need to attach the entity to a persistence context so that it becomes managed and gets persisted in the database. You can either use JPA's persist or Hibernate's save method to do that.

How do you save an object in JPA?

To persist object to database we call the EntityManager. persist() method with the entity object to be saved as the parameter. We also have to begin and commit the transaction before and after we call the persist() method. Here is the code for our DAO and its implementation.

Can we have entity without ID?

Like the text says: an entity must have an identifier to allow relationships. No identifier, no relationships. To be clear: If Customer has no id, it can still reference other entities. But it can't be referenced by others.


2 Answers

First of all, you should pay attention to your method to load an Owner entity.

If you're using an Hibernate Session :

// will return the persistent instance and never returns an uninitialized instance
session.get(Owner.class, id);

// might return a proxied instance that is initialized on-demand
session.load(Owner.class, id);

If you're using EntityManager :

// will return the persistent instance and never returns an uninitialized instance
em.find(Owner.class, id);

// might return a proxied instance that is initialized on-demand
em.getReference(Owner.class, id);

So, you should lazy load the Owner entity to avoid some hits to the cache nor the database.

By the way, I would suggest to inverse your relation between Owner and Cat.

For example :

Owner owner = ownerRepository.load(Owner.class, id);
owner.addCat(myCat);
like image 141
victor gallet Avatar answered Dec 05 '22 10:12

victor gallet


Victor's answer is correct (+1 from me), but requires going through the EntityManager or Hibernate session. Assuming the repositories you have autowired are JPA repositories from Spring Data and you would prefer to go through them, use the JpaRepository#getOne method. It calls EntityManager#getReference, so it does the same thing, returning a proxy to the entity.

I do not think the relationship necessarily needs to be reversed here, which mapping to use depends on the situation. In many cases many-to-one is preferred.

like image 27
Nathan Hughes Avatar answered Dec 05 '22 09:12

Nathan Hughes