Summarizing the comments in a reply.
You’ve fallen into a common problem with two-way relationships.
Follows a grafting of Wikibooks
Object corruption, one side of the Relationship is not updated after updating the other side
A common problem with bi-Directional relationships is the application updates one side of the Relationship, but the other side does not get updated, and Becomes out of Sync. In JPA, as in Java in general, it is the Responsibility of the application or the Object model to maintain relationships. If your application adds to one side of a Relationship, then it must add to the other side.
Making a free translation:
Object corruption, one side of the relationship is not updated after updating the other side
A common problem with bi-directional relationships is when the application updates one side of the relationship, but the other side is not updated, staying out of sync. In JPA, as in Java in general, is the responsibility of the application or the object model to maintain relationships (my emphasis). If your application adds to one side of the relationship then it should add to the other side.
In short, when you persist an object with your JPA provider it comes into existence in the persistence context. Think of the persistence context as a memory area with the objects you are manipulating; the persistence context is between the application and the database.
When you persist one Terminal
it becomes part of your persistence context. When you persist the various Portarias
with a reference to that Terminal
they also become part of the context of persistence.
Eventually your provider will write the status of the persistence context in the bank, i.e., perform insert
, delete
, update
, etc..
In your case, if you just associate the Terminal
à Portaria
, on the database side everything will occur correctly. Like the fk
is on the table portaria
, associate only the Terminal
to the concierge is sufficient for the fk
be inserted correctly.
The same does not occur with the object Terminal
present in the context of persistence. The object Terminal
managed by him has no way of knowing which new Portarias
related to it have been persisted unless you do so explicitly.
Solutions
1. Manipulate both sides of the relationship explicitly
Forget what you know about databases. If you were to update an object-oriented model without the aid of tools you would end up having to update both sides of the relationship:
portaria.setTerminal(terminal);
terminal.getPortarias().add(portaria);
2. Let your model take care of it.
We can enrich the domain to handle two-way relationships:
class Terminal {
// ...
@OneToMany(mappedBy = "terminal")
private List<Portaria> portarias;
public void adicionarPortaria(Portaria p) {
this.portariais.add(p);
if (portaria.getTerminal() != this) {
portaria.setTerminal(this);
}
}
// ...
}
And in class Portaria
:
class Portaria {
// ...
@ManyToOne
@JoinColumn(name = "terminalId", nullable = false)
private Terminal terminal;
public void setTerminal(Terminal t) {
this.terminal = t;
if (!t.getPortarias().contains(this)) {
t.getPortarias().add(this);
}
}
// ...
}
3. Assume the persistence context has been corrupted, search the bank’s information.
That’s what we did with the method refresh
:
entityManager.persist(portaria);
entityManager.refresh(terminal);
Basically what we’re doing here is telling the JPA provider: "Persist the new ordinance (with the fk
for terminal`) and "refresh" the terminal contents as per what was persisted in the database".
This is apparently the simplest of solutions, but it is also the least recommendable due to a number of problems:
- Are made
selects
unnecessary.
- The JPA provider is free to "reorder" operations in any way as well as delay writing to the bank. So we can’t always count on the state of the bank.
- In certain environments there is a second cache level. In these environments you may end up recovering a corrupted object from the cache, having the need to dislodge (
evict
) cache before refreshing the status.
4. Avoiding bi-directional relationships
This is a common maxim among more experienced developers. We don’t always need two-way relationships. When possible it is worth simplifying the model. You really need to navigate both of Terminal
for their Portarias
how much of a Portaria
back to the Terminal
? Does the complexity of introducing a bi-directional relationship really pay off compared to the complexity of doing custom queries to look the other way? These are just questions that should be asked before introducing a bi-directional relationship.
"Then I create a new Terminal, this new object does not instantiate t.getPortarias()". You identified the part of the code with problem and did not just post this part. Show this code as it seems relevant in your question.
– Caffé
@Caffé first I load a jTable with the list of Terminals, when the person selects a line, I pick the id of the record and carry an object with
em.find(Terminal.class, id)
and send it tocanDelete
which is where thet.getPortarias().isEmpty()
– Gleison