Preserve object identity in parent-child relations of a Hibernate model - java

I have the following scenario and could not find any solution for this so far.
Imagine the following Hibernate model consisting of 3 different types with one-to-many relations:
public class A {
#Transient
private String someRuntimeData;
#OneToMany
private Set<B> collA;
#OneToMany
private Set<C> collB;
}
public class B {
#ManyToOne
private A parent;
}
public class C {
#ManyToOne
private A parent;
}
Imagine that the database contains many B'c and C's that may or may not have a parent relation to A yet. I need to create an in-memory cache that contains all B's and all C's, and unfortunately there is a lot of transient data in different places involved, which requires me to suppress caching multiple instances of the same parent object A.
class SomeClass {
#Transactional
protected void init() {
bList = repoB.readAll();
cList = repoC.readAll();
}
}
The problem is that I don't know how or if it is even possible to tell JPA/Hibernate to retain and reuse an object instance (with its identity) of previously loaded entities in the following way:
Load the full collection of B's with their optional parents of A, then load the full collection of C's, where any transitively loaded instance of A (through B) is reused. Where appropriate, both B and C instances then point to the same in-memory object.
I would be very thankful if anyone could explain on how to realize this with out-of-box features of JPA/Hibernate before I swallow the bitter pill and and remap everything by hand.
Thank you in advance!

It was not obvious from the provided code snippets what the problem could have been in this scenario.
For full disclosure, the init() method was called via self-invocation from the classes constructor:
#Component
class SomeClass {
public SomeClass() {
init();
}
#Transactional
protected void init() {
bList = repoB.readAll();
cList = repoC.readAll();
}
}
Since I did not configure any aspect-weaving for load- or runtime, the compiler created a default Spring Proxy object for SomeClass. Therefore any proxy logic is fully circumvented when self-invocation is in play.
In result, the only transactions opened where the default, dedicated ones for each read operations, and the shared parent objects where redundantly loaded.

Related

Aggregate to JPA Entity mapping

In a DDD-project I'm contributing to, we're seeking for some convenient solutions to map entity objects to domain objects and visa versa.
Developers of this project agreed to fully decouple domain model from data model.
The data layer uses JPA (Hibernate) as persistence technology.
As we all reckon that persistence is an implementation detail in DDD, from a developers' point of view we're all seeking for the most appropriate solution in every aspect of the application.
The biggest concern we're having is when an aggregate, containing a list of entities, is mapped to a JPA entity that in it's turn contains a one-to-many relationship.
Take a look at the example below:
Domain model
public class Product extends Aggregate {
private ProductId productId;
private Set<ProductBacklogItem> backlogItems;
// constructor & methods omitted for brevity
}
public class ProductBacklogItem extends DomainEntity {
private BacklogItemId backlogItemId;
private int ordering;
private ProductId productId;
// constructor & methods omitted for brevity
}
Data model
public class ProductJpaEntity {
private String productId;
#OneToMany
private Set<ProductBacklogItemJpaEntity> backlogItems;
// constructor & methods omitted for brevity
}
public class ProductBacklogItemJpaEntity {
private String backlogItemId;
private int ordering;
private String productId;
// constructor & methods omitted for brevity
}
Repository
public interface ProductRepository {
Product findBy(ProductId productId);
void save(Product product);
}
class ProductJpaRepository implements ProductRepository {
#Override
public Product findBy(ProductId productId) {
ProductJpaEntity entity = // lookup entity by productId
ProductBacklogItemJpaEntity backlogItemEntities = entity.getBacklogItemEntities();
Set<ProductBacklogItem> backlogItems = toBackLogItems(backlogItemEntities);
return new Product(new ProductId(entity.getProductId()), backlogItems);
}
#Override
public void save(Product product) {
ProductJpaEntity entity = // lookup entity by productId
if (entity == null) {
// map Product and ProductBacklogItems to their corresponding entities and save
return;
}
Set<ProductBacklogItem> backlogItems = product.getProductBacklogItems();
// how do we know which backlogItems are: new, deleted or adapted...?
}
}
When a ProductJpaEntity already exists in DB, we need to update everything.
In case of an update, ProductJpaEntity is already available in Hibernate PersistenceContext.
However, we need to figure out which ProductBacklogItems are changed.
More specifically:
ProductBacklogItem could have been added to the Collection
ProductBacklogItem could have been removed from the Collection
Each ProductBacklogItemJpaEntity has a Primary Key pointing to the ProductJpaEntity.
It seems that the only way to detect new or removed ProductBacklogItems is to match them by Primary Key.
However, primary keys don't belong in the domain model...
There's also the possibility to first remove all ProductBacklogItemJpaEntity instances (which are present in DB) of a ProductJpaEntity, flush to DB, create new ProductBacklogItemJpaEntity instances and save them to DB.
This would be a bad solution. Every save of a Product would lead to several delete and insert statements in DB.
Which solution exists to solve this problem without making too many sacrifices on Domain & Data model?
You can let JPA/Hibernate solve problem for you.
public void save(Product product) {
ProductJpaEntity entity = convertToJpa(product);
entityManager.merge(entity);
// I think that actually save(entity) would call merge for you,
// if it notices that this entity already exists in database
}
What this will do is:
It will take your newly created JPA Entity and attach it
It will examine what is in database and update all relations accordingly, with priority given to your created entity (if mappings are set correctly)
This is a perfect use case for Blaze-Persistence Entity Views.
I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.
Entity views can also be updatable and/or creatable i.e. support flushing changes back, which can be used as a basis for a DDD design.
Updatable entity views implement dirty state tracking. You can introspect the actual changes or flush changed values.
You can define your updatable entity views as abstract classes to hide "implementation specifics" like e.g. the primary key behind the protected modifier like this:
#UpdatableEntityView
#EntityView(ProductJpaEntity.class)
public abstract class Product extends Aggregate {
#IdMapping
protected abstract ProductId getProductId();
public abstract Set<ProductBacklogItem> getBacklogItems();
}
#UpdatableEntityView
#EntityView(ProductBacklogItemJpaEntity.class)
public abstract class ProductBacklogItem extends DomainEntity {
#IdMapping
protected abstract BacklogItemId getBacklogItemId();
protected abstract ProductId getProductId();
public abstract int getOrdering();
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
Product p = entityViewManager.find(entityManager, Product.class, id);
Saving i.e. flushing changes is easy as well
entityViewManager.save(entityManager, product);
The Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features and for flushing changes, you can define a save method in your repository that accepts the updatable entity view
I believe you need to address the issue in a different way.
It is really hard to determine which has been changed when you have a complex graph of objects. However, there should be someone else (maybe a service) which really knows what have changed in advance.
In fact, I did not see in your question the real business "Service" or a class which address the business logic. This will be the one who can solve this issue. As a result, you will have in your repository something more specific removeProductBacklogItem(BacklogItemId idToRemove) or... addProductBacklogItem(ProductId toProductId, ProductBacklogItem itemToAdd). That will force you to manage and identify changes in other way... and the service will be responsible for.

JPA - What Annotation to use for a base class

I am a relative newbie to JPA, and I've read books (Java Persistence with Hibernate, Pro JPA 2 - Mastering the Java Persistence API), done google searches, but I have not been able to come up with a solution to the following situation.
I have a base class called History, that has all the persistent information needed to store the class's data members to a database. However, the class has an abstract method that needs to be overridden in derived classes. The derived classes do not have any persistence information of their own. They exist solely for two reasons:
to uniquely implement the abstract method defined in the base
History class
to persist the data to it's own table
The code below should make this clear.
#??? What annotation should I use here?
public abstract class History
{
#Id #GeneratedValue
private int id; // primary key
#Lob #Column(columnDefinition="mediumtext", length=65535)
protected String string; // string containing history
public abstract String foo();
}
#Entity
#Table(name="derived_history_1")
public class Derived1 extends History
{
public String foo()
{
return "Hello";
}
}
#Entity
#Table(name="derived_history_2")
public class Derived2 extends History
{
public String foo()
{
return "World";
}
}
I didn't think that #Inheritance(strategy=InheritanceType.JOINED) made sense, because nothing is being inherited in the derived classes that needs to be made persistent.
I tried #MappedSuperclass, but then the CascadeType.PERSIST and CascadeType.MERGE did not work when the derived classes were data members of another class. For example,
#Entity
#Table(name="part")
public class Part
{
...
#OneToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}, optional=false, fetch=FetchType.LAZY)
#JoinColumn(name="history_id") // foreign key into history_part table
protected Derived1 history;
}
So I couldn't find anything that worked and fit my situation.
I hope I'm explaining this well enough that people can understand.
Does anyone know how to do this that's not a complete and total hack :-)
Thanks for any help.
Following annotations should work:
#Entity
#Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
Inheritance type TABLE_PER_CLASS makes inheriting entities to create own table and you also need to tell that History is also an Entity even it does not have table of its own.

OneToMany ManyToOne removing child object with Hibernate

I'm using Spring Boot and Hibernate.
Lets assume we have two entities:
#Entity
public class A{
#OneToMany(mappedBy = "objectA",fetch = FetchType.EAGER,cascade = CascadeType.ALL,orphanRemoval=true)
private Set<B> objectSet = new HashSet<>();
}
#Entity
public class B{
#ManyToOne
private A objectA;
}
And we have two transacional methods;
deleteB_X(int idB){
entityManager.remove(entityManager.find(idB,B.class));
}
deleteB_Y(int idB){
B obj=entityManager.find(idB,B.class);
obj.getObjectA().getObjectSet().remove(obj);
}
What I understand (correct me if I'm wrong):
We have orphanRemoval=true so deleteB_Y(int) will work.
By setting mappedBy argument we say that class A is "the owning
site" of relation.
CascadeType is used when we persist/update/merge/remove class A (then it invokes persist/update/merge/remove on child property objectSet). I think we can say that it protects me from situation where I end up with object of B and no object of A class (unless we manually add some B objs).
From what I understand CascadeType should not interfare with orphanRemoval, because CascadeType takes care of things where we do 'some stuff' with A's objects (and then recursively do it to B's objects). And here is something that I don't understand at all.
Why deleteB_x(int) doesn't work and why if we remove CascadeType it starts working? I feel like that deleteB_X(int) is much cleaner solution to removing object B from the DB than deleteB_Y(int), but sadly it won't work since it colides with CascadeType.
EDIT1.
Method deleteB_X(int) just doesn't remove object from DB, if we remove cascade = CascadeType.ALL evertyhing works just fine. Why?
The issue was that my class A was fetched EAGER in class B instance and because of that (I assume) that there was a conflict when I was deleting B's instance alone without taking care of the same B instance in private Set<B> objectSet. Changing EAGER to LAZY or excluding CascadeType.PERSIST from #OneToMany(cascade=...) solved my issue.

Hibernate trying to save a detached entity - LazyInitializationException

I have the following entities:
#Entity
public class B{
#OneToMany
private List<C> cList;
private Long d;
}
In my managed bean, I need to load a specific b (which is perfectly working) in order to edit the contained attributes (cList, d):
#ManagedBean
public class Bean{
private B b;
public void onEvent(Long bId){
b = bManager.load(bId);
}
}
The attributes of B will have to be edited using a JSF-Form. I do not want these changes to be reflected to the database.
The problem is pretty much the same like in this (old) thread.
But none of the suggestions worked in my case (tried em.flush(), em.detach(), session.evict()).
Is there no solution except deep copying?
It is possible to do it, but first would be better to know what hibernate is doing and why you are getting exception. Here is documentation about object states
If you want to access list with objects C or you want to modify some of them, you must fetch it before it gets to your managed bean. By default hibernate is fetching objects lazy and associated objects will be loaded when you access them, but preconditions is to have a transaction and session attached to objects. So in your managed bean objects are detached and list of C cannot be fetch at that time. To solve that problem you must fetch all object that you want to change before they gets to the managed bean. i.e.
#OneToMany
#Fetch(FetchMode.JOIN) // load it with sql join
private List<C> cList;
There many other ways you can achieve same result. So now you can update your B and list of C
entities and then call update function for your B entity.
Hope it helps.

What is appropriate way of creating objects with One-to-Many relationship using Objectify and RequestFactory?

What is appropriate way of creating objects with One-to-Many relationship using Objectify and RequestFactory? I've read documentation for these libraries, and also reviewed number of sample projects such as listwidget and gwtgae2011. All of them use #Embedded annotation which is not what I want because it stores everything within one entity. Another option according to documentation would be to use #Parent property in child classes. In my example (getters/setters removed for simplicity) I have entities Person and Organization which defined as
#Entity
public class Person extends DatastoreObject
{
private String name;
private String phoneNumber;
private String email;
#Parent private Key<Organization> organizationKey;
}
and
#Entity
public class Organization extends DatastoreObject
{
private String name;
private List<Person> contactPeople;
private String address;
}
Now if I understood documentation correctly in order to persist Organization with one Person I have to persist Organization first, then set organizationKey to ObjectifyService.factory().getKey(organization) for Person object and then persist it. I already don't like that I have to iterate through every child object manually but using RequestFactory makes everything is more convoluted due to presence of proxy classes. How would I define Organization and OrganizationProxy classes - with Key<> or without it ? Will I have to define something like this in Organization ?
public void setContactPeople(List<Person> contactPeople)
{
for (int i = 0; i < contactPeople.size(); ++i)
{
DAOBase dao = new DAOBase();
Key<Organization> key = dao.ofy().put(this);
contactPeople.get(i).setOrganizationKey(key);
}
this.contactPeople = contactPeople;
}
And how would I load Organization with its children from Datastore ? Will I have to manually fetch every Person and fill out Organization.contactPeople in #PostLoad method ?
It seems like I'll have to write A LOT of maintenance code just to do what JPA/JDO does behind the scene. I simply don't get it :(
Am I missing something or it's the only way to implement it ?
Thanks a lot for answers in advance!!!
You need to make it as #Parent only when you going to use it in transaction against all Person in this Organization. I'm sure it's not what you want.
It's enough to save just private Key<Organization> organizationKey, and filter by this field when you need to find Person for specified Organization
As about loading all referenced objects - yes, it is, you have to load it manually. It's pita, but it's not a lot of code.
Also, there is a different way to store this relationship, if your organization are small enough, and consists of few hundreds of people. At this case you can have List<Key<Person>> contactPeopleKey;, and load all this people by existing Key, manually, it much be much faster than loading by new Query

Categories