I have what I would think is a fairly typical setup in EclipseLink, although admittedly I am a bit new to EclipseLink. I've worked with Persistence and Hibernate a bit, but usually through some convenience wrappers and such and not as directly as I am here. Persisted class A contains a list of persisted class B. It's annotated as follows:
public class A {
#OneToMany(fetch = FetchType.EAGER, targetEntity = B.class, cascade = CascadeType.ALL, mappedBy = "fieldA")
#PrivateOwned
#CascadeOnDelete
private List<B> bItems;
}
public class B {
#ManyToOne(targetEntity = A.class, fetch = FetchType.EAGER)
#JoinColumn(name = "JOIN_COL")
private A aItem;
}
The creation and editing of these objects is working just fine. When an object A is deleted, it cascades as it should and any B objects tied to it are cleared out as well. The issue I'm hitting is trying to clear B objects from A directly. Normally this is done via a UI with some intermediary DTO objects between. That's working fine. However, I have some backend code that needs to clear out all of Object B directly from the domain object A in certain circumstances. It seems that using:
itemA.getBItems().clear();
is not working. I would think that this should be picked up by the EntityManager (which is done with a simple entityManager.persist(objectA) in a service class), but it's not clearing the associated B objects in the database. Is that simply the nature of the way I'm doing it or even the way the ArrayList class implements clear() (I'd try some other methods, but the nature of the beast in this case makes it difficult and time-consuming to properly test), or do I need to get a bit more fine grained on how I do this? Perhaps my annotations are a bit off? Or perhaps I'm doing things correctly but need to add a convenience method to the service class that clears out the B objects via the EntityManager and evicts any relevant caches?
Related
In a bidirectional mapping between entities (e.g. #ManyToOne ↔ #OneToMany), the counterpart needs to be synchronized on every change, especially when using a 2nd level cache. This is usually done with helper methods. Those helper methods do not perform well if the Many part contains a lot of entries, because the whole set is fetched each time. A simple example would be an entity Store which has n Products, whereas n is very large. Adding a new Product to the Store would require the Store to fetch the whole list of Products to finally add it to the set (see code example below).
One could argue, that when modelling such a relation it would be better represented with an unidirectional association from the Product to the Store. We are using many JPQL queries in our application though. In JPQL, it comes very handy to join entities from both sides.
Do you see any problems when mapping the #OneToMany relation in the Store entity, when Many actually means many and not just a few, and just make the field private, without getters and setters, provided that the whole relation is lazily fetched? As I understand, Hibernate just needs the field to map the relation. And if the set is private, no performance issues should occur?
The Product entity:
#Entity
#Table(name = "product")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Product {
#ManyToOne(fetch = FetchType.LAZY)
private Store store;
// setter, getter, helper methods
}
The Store entity:
#Entity
#Table(name = "store")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Store {
#OneToMany(mappedBy = "products", fetch = FetchType.LAZY)
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Product> products;
// setter, getter, helper methods
}
No, there is nothing wrong with it, it's a technique I've used often as well. Of course just make sure that the field is not accessed reflectively in some context (like automatic toString builders and similar utilities you may be using).
Also, you don't need the #Cache annotation on it since you will never access the collection anyway, thus it will never be cached.
I'm trying to figure out a cleaner way of saving a join table back to the database using only the entity id of the two joined tables. I can make my code work as is, but I feel like there should be a cleaner manner.
Imagine I have an entity which represents a simple sql join table, so something like this:
#Entity
#Table(name = "FOOBAR")
public class FooBar{
#ManyToOne(fetch = FetchType.Lazy)
#JoinColumn(name = "FOO_ID)
public Foo foo;
#ManyToOne(fetch = FetchType.Lazy)
#JoinColumn(name = "BAR_ID)
public Bar bar;
public FooBar(Foo foo, Bar bar){
this.foo=foo;
this.bar=bar;
}
}
I have a method which takes a Foo id and a Bar id, and wants to pass a FooBar object to my save method to save the join.
A naive implementation would query the database to find the Foo and Bar objects based off of their ids, pass those into the FooBar constructor, and then pass the new FooBar to the save method.
However, this is silly, the only things my join table needs is the foo and bar ids, not the full DB objects. I have everything I need already without hitting the DB to fetch Foo and Bar.
In fact I could simply construct a Foo object and bar object using their a public ID, ignoring all the other fields of the objects, create a FooBar object from these two 'empty' foo and bar objects, and pass that to save and it would work just fine without extra DB hits.
However, it somehow feels a little unclean to do this. I'm creating two 'dummy' objects this way. My foo and bar objects may have some nullable = false columns which my DB contract promises will never be null, so it feels wrong constructing a foo object that does have null fields for these columns; as if I'm breaking the contract for these objects. I don't want a constructor for either object that accepts only an ID because; I want to force them to be constructed in a manner that abides by my contract any time someone constructs them. I would prefer not to have to knowingly create objects that violate my promise.
I'm wondering if there is a way through JPA, or some quickly written abstraction I could do, to build my FooBar object using only the foo and bar ids in a way that is clean and communicative and does not violate any of the Foo/Bar constraints. After all since both Foo and Bar are lazy loaded when I first get a FooBar object all it really contains are the foo and bar ids until I call the getter; so I contain as much information already as a FooBar object from the DB would have.
can I create a FooBar object with only their ID and have that object tied to the DB, so it would lazy load the Foo and Bar objects if the getter were called just like a FooBar I get from the DB does?
Having a class for a join table is overkill.
JPA has the ManyToMany annotation, which creates the relationship for you.
You basically need to choose one of the entities to "own" the relationship. This is more or less which class defines the table being used for the join.
In this case, I'll choose Foo as the one that owns the relationship.
In Foo, you can do this:
#ManyToMany
#JoinTable(name="FOOBAR", joinColumns=#JoinColumn(name="FOO_ID"),
inverseJoinColumns=#JoinColumn(name="BAR_ID"))
public Set<Bar> bars;
and in Bar:
#ManyToMany(mappedBy="bars")
public Set<Foo> foos;
Note, although I used Set, you can use List instead.
Note: ManyToMany is Lazy by default... and I suggest leaving it that way.
The entityManager#getReference seems to be what you are looking for. It creates and returns an object that can be used wherever a reference to an entity is required and can (but in your case, will not have to) have all its state fetched lazily.
lets say i have the following POJO Class
public class Example {
private String name;
private int id;
private Object o;
// more fields
// getter/Setter
Now lets assume i want to persist my Entity using JPA i will come on with the following example POJO Class:
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private int id;
#OneToMany(mappedBy = "directive")
private String name;
In my Opinion this is bad, becaus if i want to use e.g. Spring Data MongoDB the Annotations would be useless/false.
The only why i can think of to avoid this, is defining an Interface or an Abstract class, for example Storable, which defines getter/setter methods.
But then i have violated the POJO definition (and one can argue it was not a Pojo to begin with).
Are there any best Practices for defining Model Classes?
When using JPA, you can leave you classes untouched and have ALL your configuration in XML files. Many people prefer annotations, but if changing the persistence implementation is a requirement, you should consider using external configuration.
I am not sure about other frameworks/specs besides JPA, but XML configuration goes a long way in java. I am sure, many frameworks offer such possibilities.
There is also a pattern called DTO (data transfer objects) that can be used for separation of persistence concerns from business concerns.
The gist is: you use your annotated, DB-centric classes for your DB connection only. Your main application only uses business-oriented classes and is persistence-agnostic. The data could come from a DB or from a flat file, as long as you can convert it to you business objects, all is well.
EDIT: DTOs sound like a lot of work, but you gain clarity and testability by separating concerns. hexagonal architecture and clean architecture emphasize this approach.
I'm currently studying the official JPA 2 final specification.
Is the following statement contained anywhere in the Spec?
The Entity Manager guarantees that within a single Persistence Context,
for any particular database row, there will be only one object
instance.
Either I don't clearly understand the spec or I just can't find the part that proves that the quoted statement is part of the specification.
No, specification does not give such a guarantee. But in my opinion it is implicitly assumed.
In practice sometimes same table is mapped to the two different entities. One of them being treated as read only entity. Read only entity can for example be used for reporting purposes and as an optimization contains only subset of fields in other entity. This can be done for example as follows:
#Entity
public class EntityA {
#Id private Integer id;
#Lob
byte[] tooHeavyToLoadAlways;
}
#Entity
#Table(name="EntityA")
public class EntityALightWeight {
#Id private Integer id;
}
For JPA there is no connection between these two entities, so keeping care that only first one of them is modified and that second one is refreshed is responsibility of application. Because of that should be used only with caution, because EntityALightWeight can be refreshed from database but will never contain changes made to the EntityA in same transaction.
Assume we have following JPA Entities:
class Parent {
#Id
private Long id;
}
class Child {
#Id
private Long id;
#Column
private String name;
#ManyToOne(fetch = FetchType.LAZY)
private Parent parent;
}
Let's assume a Child can uniquely be identified by its name on the Parent (combination of both). So, Parent and name can be considered as the business key of a Child.
I am unsure now what the best approach would be to implement equals (and hashCode) on the class Child.
Reference the id of the application
Since the Application proxy will be loaded and its id will be set on the proxy so the Application entity itself would not be initialized:
public boolean equals (Object o) {
//null check, instanceof check ...
return new EqualsBuilder().append(getName(), other.getName())
.append(getParent().getId(), other.getParent().getId())
.isEquals();
}
This will do the trick but I see some downsides as well. First (minor), an extra not null check on the parent would probably be advisable which makes your equals methods less compound.
Next (less minor), This would required hibernate to access the properties rather than the fields; so, I would need to set the annotations on the getters instead of on the fields. This is something I can live with personally but the habit in the current project is to put the annotations on field level.
Don't use the referenced entity for evaluating equality
Ok, but then I need something else. I don't want to use the id of the Child (bad practice) which leaves me with only 1 option: using a separate property for this, like a UUID. I have nothing against the use of UUID's but of course only if there is no other option available.
My questions are:
Did I miss an option?
What, in your opinion, would be the advised way of doing this?
Another possibility would be to add another field containing the foreign key to the parent which can then be used in the equals and hashCode methods without fetching the referenced entity:
#Column(name="parent_id", insertable=false, updatable=false)
private String parentId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="parent_id")
private Parent parent;
If you can get hold of the EntityManagerFactory (and if you can get hold of the EntityManager, EntityManager.getEntityManagerFactory() is one way to do it), another way to get the parent's ID is with:
emf.getPersistenceUnitUtil().getIdentifier(parent);
You'd still need a null check, though.