JPA mapped tree structure with inheritance - java

I'm trying to implement a tree structure in JPA, that I want mapped to an H2 database using EclipseLink. The nodes of the tree are possibly subclasses of the base node class. What is happening is that EL is creating a brain-dead link table for the children as follows:
[EL Fine]: sql: 2015-04-10 13:26:08.266--ServerSession(667346055)--Connection(873610597)--CREATE TABLE ORGANIZATIONNODE_ORGANIZATIONNODE (OrganizationNode_IDSTRING VARCHAR NOT NULL, children_IDSTRING VARCHAR NOT NULL, Device_IDSTRING VARCHAR NOT NULL, monitors_IDSTRING VARCHAR NOT NULL, PRIMARY KEY (OrganizationNode_IDSTRING, children_IDSTRING, Device_IDSTRING, monitors_IDSTRING))
OrganizationNode is the proper superclass of Device. Both of these are #Entity, OrganizationNode extends AbstractEntity, which is a #MappedSuperclass where the #Id is defined (it is a string). Even stranger, while there is a Monitor class that is not in the tree structure, the only place "monitors" plural occurs is as a field of Device... what??
Now, it's fine to use a table like that to implement a tree structure, but I don't expect a compound primary key with separate instances of the Id field for each subclass! That's got to break - because some children are not Device, and therefore do not have a "Device_IDSTRING", and sure enough:
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.DatabaseException|Internal Exception: org.h2.jdbc.JdbcSQLException: NULL not allowed for column "DEVICE_IDSTRING"; SQL statement:|INSERT INTO ORGANIZATIONNODE_ORGANIZATIONNODE (children_IDSTRING, OrganizationNode_IDSTRING) VALUES (?, ?) [23502-186]|Error Code: 23502|Call: INSERT INTO ORGANIZATIONNODE_ORGANIZATIONNODE (children_IDSTRING, OrganizationNode_IDSTRING) VALUES (?, ?)|?bind => [2 parameters bound]|Query: DataModifyQuery(name="children" sql="INSERT INTO ORGANIZATIONNODE_ORGANIZATIONNODE (children_IDSTRING, OrganizationNode_IDSTRING) VALUES (?, ?)")
This seems like truly bizarre behavior. I've tried every combination of mapping annotations I could possibly think of to fix it. Any ideas?
Classes follow.
AbstractEntity.java:
#MappedSuperclass
public abstract class AbstractEntity {
// #Converter(name="uuidConverter",converterClass=UUIDConverter.class)
transient UUID id = null;
#Id String idString;
static long sequence = 1;
static long GREGORIAN_EPOCH_OFFSET = 12219292800000L;
public AbstractEntity() {
ThreadContext tctx = ThreadContext.getThreadContext();
long msb = tctx.getNodeID();
long lsb = (System.currentTimeMillis()+GREGORIAN_EPOCH_OFFSET) * 1000 + ((sequence++) % 1000);
lsb = (lsb & 0xCFFFFFFFFFFFFFFFL) | (0x8000000000000000L);
msb = (msb & 0xFFFFFFFFFFFF0FFFL) | (0x0000000000001000L);
id = new UUID(msb,lsb);
idString = id.toString();
}
#Id
public UUID getUUID() {
return id;
}
public String getIdString() {
return idString;
}
public void setIdString(String idString) {
this.idString = idString;
this.id = UUID.fromString(idString);
}
void setUUID(UUID id) {
this.id = id;
this.idString = id.toString();
}
#Override
public String toString() {
return "["+this.getClass().getCanonicalName()+" "+this.getUUID()+"]";
}
}
OrganizationNode.java:
#Entity
public class OrganizationNode extends AbstractEntity {
#ManyToOne(cascade=CascadeType.ALL)
NodeType nodeType;
#Column(nullable=true)
String name;
#OneToMany(cascade=CascadeType.ALL)
Set<OrganizationNode> children;
public OrganizationNode() {}
public OrganizationNode(NodeType nt, String name) {
this.nodeType = nt;
this.name = name;
children = new HashSet<>();
}
public void setNodeType(NodeType nt) {
nodeType = nt;
}
public NodeType getNodeType() {
return nodeType;
}
public String getName() {
if ((name == null) || (name.equals(""))) return null;
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<OrganizationNode> getChildren() {
return children;
}
public void setChildren(Set<OrganizationNode> children) {
this.children = children;
}
public void addNode(OrganizationNode node) {
children.add(node);
}
public void removeNode(OrganizationNode node) {
children.remove(node);
}
}
Device.java:
#Entity
public class Device extends OrganizationNode {
Set<Monitor> monitors;
public Device() {
super();
}
public Device(NodeType nt, String name) {
super(nt, name);
monitors = new HashSet<>();
}
public Set<Monitor> getMonitors() {
return monitors;
}
public void setMonitors(Set<Monitor> monitors) {
this.monitors = monitors;
}
public void addMonitor(Monitor monitor) {
monitors.add(monitor);
}
}

You need to decide what inheritance startegy you want to use.
The default one is typically the "Single Table Inheritance" so all the subclasses are represented in one table with merged columns.
#Inheritance
#Entity
public class OrganizationNode extends AbstractEntity {
...
}
and you saw it the sql.
You can have Joined, Multiple Table Inheritance where each subclass has its own table and are joined with parent table:
#Inheritance(strategy=InheritanceType.JOINED)
Finally, the last option is Table Per Class Inheritance, where there is no "inheritance" tree reflected in the tables structure, and each object has its full table with all the columns from the class and supperclasses.
#Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
The last one is the least efficient.
You can have only one strategy, which you define on the top of the inheritance (OrganizationNode), it cannot be changed in subclasses.
The default single table inheritance is typically the most efficient unless there are really a lot of columns which are not shared between the classes
You should probably explicitly declare column which will be used to deteriment the actual class type: #DiscriminatorColumn(name="NODE_TYPE") and for each Entity define the value: #DiscriminatorValue("TYPE1")

Related

How to map foreign key attribute to record in Java with JDBI

Say my DB looks like this, presenting using POJO:
class A {
long id; // auto-increment primary key
String aAttribute;
}
class B {
long id; // auto-increment primary key
long aId; // foreign key of class A
String bAttribute;
}
How could I naturally map the DB records to class B using JDBI so the class B could contain the actual object of A instead of a foreign key to A:
class B {
long id; // auto-increment primary key
A a; // actual object of class A
String bAttribute;
}
One approach (there are others, also) is to use the JDBI #Nested annotation with a bean mapper. The annotation:
"...creates a mapper for the nested bean."
Place the annotation on the relevant setter (or getter). So, in your case that would be like this:
import org.jdbi.v3.core.mapper.Nested;
import org.jdbi.v3.core.mapper.reflect.ColumnName;
public class B {
private long id; // auto-increment primary key
private A a; // actual object of class A
private String bAttribute;
#ColumnName("b_id")
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public A getA() {
return a;
}
#Nested
public void setA(A a) {
this.a = a;
}
#ColumnName("b_attribute")
public String getBAttribute() {
return bAttribute;
}
public void setBAttribute(String bAttribute) {
this.bAttribute = bAttribute;
}
}
I have also added #ColumnName annotations to disambiguate the otherwise identical column names between the two objects (and, presumably, the tables).
Here is class A:
package com.northcoder.jdbidemo;
import org.jdbi.v3.core.mapper.reflect.ColumnName;
public class A {
private long id; // auto-increment primary key
private String aAttribute;
#ColumnName("a_id")
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
#ColumnName("a_attribute")
public String getAAttribute() {
return aAttribute;
}
public void setAAttribute(String aAttribute) {
this.aAttribute = aAttribute;
}
}
A query therefore needs to use column aliases to match these annotations:
String sql = """
select b.id as b_id, b.bAttribute as b_attribute, a.id as a_id, a.aAttribute as a_attribute
from your_db.a as a
inner join your_db.b as b
on a.id = b.a_id;
""";
jdbi.useHandle(handle -> {
List<B> bees = handle
.select(sql)
.mapToBean(B.class)
.list();
});
Each instance of class B in the resulting list will contain an instance of A (assuming the data exists in the database).

Strict column checking in Datastax java driver 4 causing problems

Below is our entity class
#Entity(defaultKeyspace = CASSANDRA_KEYSPACE)
#CqlName(CASSANDRA_TABLE)
public static class Scientist implements Serializable {
#CqlName("person_name")
public String name;
#Computed("writetime(person_name)")
#CqlName("name_ts")
public Long nameTs;
#CqlName("person_id")
#PartitionKey
public Integer id;
public Scientist() {}
public Scientist(int id, String name) {
super();
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return id + ":" + name;
}
#Override
public boolean equals(#Nullable Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Scientist scientist = (Scientist) o;
return id.equals(scientist.id) && Objects.equal(name, scientist.name);
}
#Override
public int hashCode() {
return Objects.hashCode(name, id);
}
}
#Dao
public interface ScientistDao {
#GetEntity
MappedAsyncPagingIterable<Scientist> map(AsyncResultSet resultSet);
#Delete
CompletionStage<Void> deleteAsync(Scientist entity);
#Insert
CompletionStage<Void> saveAsync(Scientist entity);
}
The problem faced is, when the computed fields (in the above case writetime(person_name) )are not selected as part of the query, the mapping fails.
In 3.x driver: mapped fields that are not present in the ResultSet were ignored. link
In 4.x driver: for each entity field, the database table or UDT must contain a column with the corresponding name. link
Please suggest a possible solution/workaround where this computed field can be part of the query on a need basis and the mapping happens successfully without throwing IllegalArgumentException.
Edit:
scientist table schema
CREATE TABLE beam_ks.scientist (person_id int PRIMARY KEY,person_name text);
Below is the query tried:
select person_id,writetime(person_name) as name_ts from beam_ks.scientist where person_id=10
Mapping of the resultset with #GetEntity fails with below error:
Caused by: java.lang.IllegalArgumentException: person_name is not a column in this row
at com.datastax.oss.driver.internal.core.cql.DefaultRow.firstIndexOf(DefaultRow.java:110)
at com.datastax.oss.driver.api.core.data.GettableByName.get(GettableByName.java:144)
at org.apache.beam.sdk.io.cassandra.CassandraIOTest_ScientistHelper__MapperGenerated.get(CassandraIOTest_ScientistHelper__MapperGenerated.java:89)
get method in CassandraIOTest_ScientistHelper__MapperGenerated:
#Override
public CassandraIOTest.Scientist get(GettableByName source) {
CassandraIOTest.Scientist returnValue = new CassandraIOTest.Scientist();
Integer propertyValue = source.get("person_id", Integer.class);
returnValue.setId(propertyValue);
String propertyValue1 = source.get("person_name", String.class);
returnValue.setName(propertyValue1);
return returnValue;
}
Also, the documentation does not specify whether to add getter and setter methods for computed values. So, they are removed from entity class
When using #GetEntity methods, it is your responsibility to provide a result set object that is 100% compatible with the entity definition.
Here your Scientist entity contains two regular fields: person_id (integer) and person_name (text). Therefore your result set must contain (at least) two columns with these names and types.
But you said you provided the following query: select person_id,writetime(person_name) as name_ts from beam_ks.scientist where person_id=10.
This query does not contain the required columns. You should change your query to the one below, or something similar:
select person_id, person_name from beam_ks.scientist where person_id=10
Note that #GetEntity methods do not recognize computed values, only regular ones. It is not necessary to include writetime(person_name) as name_ts, it won't be mapped anyway.

Hibernate mapping and Unique index or primary key violation

I am new in hibernate, and I am experiencing the following problem. "Unique index or primary key violation". The problem appears due to the wrong mapping, but I spend hours to figure out why it is happening.
I have one super class called DataStructure
#Entity
#Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public abstract class DataStructure {
private int DS_ID;
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
public int getDataStructureID() {
return DS_ID;
}
Then the class Association which associate two elements. Some parts of the class are omitted here, just to simplify it.
#Entity
public class AssociationTemporal extends DataStructure {
private DataStructure elementA;
private DataStructure elementB;
#OneToOne
public DataStructure getElementA() {
return elementA;
}
public void setElementA(DataStructure elementA) {
this.elementA = elementA;
}
#OneToOne
public DataStructure getElementB() {
return elementB;
}
public void setElementB(DataStructure elementB) {
this.elementB = elementB;
}
}
This class serves as middle class between two classes of DataStructure type. Like this.
TP-Association-TP
TP class:
#Entity
public class TP extends DataStructure {
List<AssociationTemporal> listOfAssociatedTPs = new ArrayList<AssociationTemporal>();
#OneToMany
public List<AssociationTemporal> getListOfAssociatedTPs() {
return listOfAssociatedTPs;
}
public void setListOfAssociatedTPs(List<AssociationTemporal> listOfAssociatedTPs) {
this.listOfAssociatedTPs = listOfAssociatedTPs;
}
}
Or activites class
#Entity
public class Activities extends DataStructure {
String name;
List<AssociationTemporal> listOfAsso = new ArrayList<AssociationTemporal>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#OneToMany
public List<AssociationTemporal> getListOfAsso() {
return listOfAsso;
}
public void setListOfAsso(List<AssociationTemporal> listOfAsso) {
this.listOfAsso = listOfAsso;
}
}
In the main I have added the following:
AssociationTemporal at = new AssociationTemporal();
TP tp1 = new TP();
TP tp2 = new TP();
at.setElementA(tp1);
at.setElementB(tp2);
session.save(tp1);
session.save(tp2);
session.save(at);
tp1.getListOfAssociatedTPs().add(at);
tp2.getListOfAssociatedTPs().add(at);
session.getTransaction().commit();
The problem occurs as soon as I try to add the same object of
tp1.getListOfAssociatedTPs().add(at);
tp2.getListOfAssociatedTPs().add(at);
Caused by: org.h2.jdbc.JdbcSQLException: Unique index or primary key violation: "UK_12JEPI3MP039NKMGO47YW1HBI_INDEX_A ON PUBLIC.TP_ASSOCIATIONTEMPORAL(LISTOFASSOCIATEDTPS_DATASTRUCTUREID) VALUES (32770, 1)"; SQL statement:
insert into PUBLIC.TP_AssociationTemporal (TP_dataStructureID, listOfAssociatedTPs_dataStructureID) values (?, ?) [23505-183]
By the same mean the association can be made with Activities, etc...
Just use GenerationType.SEQUENCE and it will fix the problem.

JPA eclipselink Inheritance between entities : oracle database

I'm facing a little problem with my web application which is in vaadin and i'm using jpa and eclipselink for the mapping. I have three entities :
encaiss (#MappedSuperclass contains just Id)
|
|
Encaissement (it contains the main and common properties)
/ \
/ \
Encaissement_Technique Encaissement_espece
When i create an entity "Encaissement" with "Espece" as type, it is well created in the table Encaissement but it doesn't exist in the table Encaissement_espece.
I guess that I should join the two tables according to the identifier (ID) which is in a #MappedSuperclass class. I would appreciate any help for managing my subordinate class (that is Encaissement_Technique and Encaissement_espece) because my next step would be to add records to those two tables from a simple form (so if i have a field "libelle" which is present in Encaissement but not in Encaissement_Espece how can make such instruction :
Encaissement_Espece espece= new Encaissement_Espece();
espece.setLibelle(field.getValue().toString());
Those are my entities :
encaiss, this class contain just the Id for all the classes
#MappedSuperclass
public abstract class encaiss {
#Id
#GeneratedValue(strategy=GenerationType.AUTO, generator="encaiss_seq_gen")
#SequenceGenerator(name="encaiss_seq_gen", sequenceName="ENCAISSEMENT_SEQ", allocationSize = 1, initialValue = 1)
protected Integer id_encaissement;
public Integer getId_encaissement() {
return id_encaissement;
}
public void setId_encaissement(Integer id_encaissement) {
this.id_encaissement = id_encaissement;
}
}
Encaissement (wich extend encaiss just to have an Id)
#Entity
#Inheritance(strategy=InheritanceType.JOINED)
#DiscriminatorColumn(name="ENCAISS_TYPE")
#Table(name="ENCAISSEMENT")
public class Encaissement extends encaiss implements Serializable{
#ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
#JoinColumn(name = "ID_CLIENT")
private Client Client;
#Column(name="ENCAISS_TYPE")
protected String encaiss_type;
#Column(name="LIBELLE")
protected String libelle;
#Column(name="PIECE_JOINTE")
protected String piece_jointe;
#Embedded
protected Avis_Recette avis_recette;
public Encaissement(String encaiss_type, String libelle, String piece_jointe){
this.encaiss_type=encaiss_type;
this.libelle=libelle;
this.piece_jointe=piece_jointe;
}
public Encaissement(){
}
}
Encaissement_Espece, inherits from Encaissement
#Entity
#DiscriminatorValue("Espece")
#Table(name="ENCAISSEMENT_ESPECE")
public class Encaissement_Espece extends Encaissement{
public Caisse getCaisse() {
return caisse;
}
public void setCaisse(Caisse caisse) {
this.caisse = caisse;
}
public float getMontant() {
return montant;
}
public void setMontant(float montant) {
this.montant = montant;
}
#ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
#JoinColumn(name = "ID_CAISSE")
private Caisse caisse;
#Column(name = "MONTANT")
private float montant;
public Encaissement_Espece(float montant){
this.montant=montant;
}
public Encaissement_Espece(){
}
}
Encaissement_Technique, inherits from Encaissement
#Entity
#DiscriminatorValue("Technique")
#Inheritance(strategy=InheritanceType.JOINED)
#DiscriminatorColumn(name="ENCAISS_TECHNIQUE_TYPE")
#Table(name="ENCAISSEMENT_TECHNIQUE")
public class Encaissement_Technique extends Encaissement implements Serializable{
public Banque getBanque() {
return banque;
}
public void setBanque(Banque banque) {
this.banque = banque;
}
public float getPrimeCoass() {
return primeCoass;
}
public void setPrimeCoass(float primeCoass) {
this.primeCoass = primeCoass;
}
public Set<Periode> getPeriode() {
return periode;
}
public void setPeriode(Set<Periode> periode) {
this.periode = periode;
}
public String getEncaiss_technique_type() {
return encaiss_technique_type;
}
public void setEncaiss_technique_type(String encaiss_technique_type) {
this.encaiss_technique_type = encaiss_technique_type;
}
#Column(name="PRIMECOASS")
protected float primeCoass;
#Column(name="ENCAISS_TECHNIQUE_TYPE")
protected String encaiss_technique_type;
public Encaissement_Technique(float primeCoass, String encaiss_technique_type){
this.primeCoass=primeCoass;
this.encaiss_technique_type=encaiss_technique_type;
}
public Encaissement_Technique(){
}
}
I hope i will find a pertinent answer as i searched for this in vain. It'll help me a lot.
Thank you.
"When i create an entity "Encaissement" with "Espece" as type, it is well created in the table Encaissement but it doesn't exist in the table Encaissement_espece." This statement suggests you have an instance of Encaissement and expect JPA to turn it into an instance of Encaissement_Espece just by changing the encaiss_type value. Java object inheritance doesn't work that way, which is what JPA inheritance tries to map to a relational database. An object in java cannot change what it is simply by setting a flag - you need to create a new instance if you want the data represented differently.
In this case, you need to create an instance of the Encaissement_Espece class. Because this class maps to the Encaissement and Encaissement_espece tables, JPA will automatically insert a row into both to represent this object. When you create Encaissement instance, a row goes into the Encaissement table, while when you create Encaissement_Technique instances, a row goes into both Encaissement_Technique and Encaissement tables. If you wish to change the object's type once it is persisted, you need to remove the old instance, flush, then persist the new one.
As mentioned in another answer, the encaiss_type is controlled through the class type itself and so does not need a mapping. Having one might be handy for queries or access (though you can just use instance of etc); it should be marked as insertable=false, updatable=false so that you do not attempt to modify the value directly.
remove the
#Column(name="ENCAISS_TYPE")
protected String encaiss_type;
from the Encaissment.
It will be handle automatically by JPA. It should solve the problem.

JPA - Using insertable/updatable

I am writing a webservice to maintain a database. I am trying to use JPA (EclipseLink) for the entity classes. However, the database uses natural primary keys and therefore there's potential that an update on the ID fields will fail due to foreign key constraints. Our DBA has provided a function to update the ID fields which will create a new parent record with the updated ID, update the child records to point to the new parent and delete the old parent.
If the ID fields could be updated "normally", I would have a situation like this:
#Entity
#Table(name = "PARENT")
public class Parent implements Serializable
{
private static final long serialVersionUID = 1L;
private String parent;
private String attribute;
private Set<Child> childs;
public Parent()
{
}
#Id
#Column(name = "PARENT")
public String getParent()
{
return this.parent;
}
public void setParent(String parent)
{
this.parent = parent;
}
#Column(name = "ATTRIBUTE")
public String getAttribute()
{
return this.attribute;
}
public void setAttribute(String attribute)
{
this.attribute = attribute;
}
#OneToMany(mappedBy = "parentBean")
public Set<Child> getChilds()
{
return this.childs;
}
public void setChilds(Set<Child> childs)
{
this.childs = childs;
}
}
#Entity
#Table(name = "CHILD")
public class Child implements Serializable
{
private static final long serialVersionUID = 1L;
private String child;
private String attribute;
private Parent parentBean;
public Child()
{
}
#Id
#Column(name = "CHILD")
public String getChild()
{
return this.child;
}
public void setChild(String child)
{
this.child = child;
}
#Column(name = "ATTRIBUTE")
public String getAttribute()
{
return this.attribute;
}
public void setAttribute(String attribute)
{
this.attribute = attribute;
}
#ManyToOne
#JoinColumn(name = "PARENT")
public Parent getParent()
{
return this.parent;
}
public void setParent(Parent parent)
{
this.parent = parent;
}
}
I also have a GenericServiceBean class with a method to call functions:
#Stateless
public class GenericServiceBean implements GenericService
{
#PersistenceContext(unitName = "PersistenceUnit")
EntityManager em;
public GenericServiceBean()
{
// empty
}
#Override
public <T> T create(T t)
{
em.persist(t);
return t;
}
#Override
public <T> void delete(T t)
{
t = em.merge(t);
em.remove(t);
}
#Override
public <T> T update(T t)
{
return em.merge(t);
}
#Override
public <T> T find(Class<T> type, Object id)
{
return em.find(type, id);
}
. . .
#Override
public String executeStoredFunctionWithNamedArguments(String functionName,
LinkedHashMap<String, String> namedArguments)
{
Session session = JpaHelper.getEntityManager(em).getServerSession();
StoredFunctionCall functionCall = new StoredFunctionCall();
functionCall.setProcedureName(functionName);
functionCall.setResult("RESULT", String.class);
for (String key : namedArguments.keySet())
{
functionCall.addNamedArgumentValue(key, namedArguments.get(key));
}
ValueReadQuery query = new ValueReadQuery();
query.setCall(functionCall);
String status = (String)session.executeQuery(query);
return status;
}
}
If I set the ID fields to be not editable:
#Id
#Column(name = "PARENT", udpatable=false)
public String getParent()
{
return this.parent;
}
and call parent.setParent(newParent) will this still update the ID in the entity object? How does this affect any child entities? Will they also be updated (or not)?
Another scenario I don't know how to deal with is where I need to update both the ID and another attribute. Should I call the function which updates (and commits) the ID in the database then make calls to set both the ID and attribute via the normal set* methods and then the persistence context will only commit the attribute change?
Perhaps this is a situation where JPA is not appropriate?
Any advice on this is greatly appreciated.
If I set the ID fields to be not editable (...) and call parent.setParent(newParent) will this still update the ID in the entity object? How does this affect any child entities? Will they also be updated (or not)?
updatable=false means that the column won't be part of the SQL UPDATE statement regardless of what you do at the object level so the Id shouldn't be updated. And I'm also tempted to say that child entities shouldn't be affected, especially since you're not cascading anything.
Another scenario I don't know how to deal with is where I need to update both the ID and another attribute (...)
Well, my understanding is that you'd have to call the function anyway so I would call it first.
Perhaps this is a situation where JPA is not appropriate?
I'm not sure raw SQL would deal better with your situation. Actually, the whole idea of changing primary keys sounds strange if I may.

Categories