Sorry about the somewhat vague title; this is easier to illustrate in code. I had a BeforeInsertEntityListener which creates a new access group when a specific entity type is created, which worked just fine until I changed the entity type to extend a non-mapped superclass.
Firstly, here’s the code which works:
(All of my entites were created using Studio, so there’s no custom code involved except in the listener.)
ConcreteEntity
@Listeners("app_ConcreteEntityListener")
@Table(name = "APP_CONCRETE_ENTITY")
@Entity(name = "app$ConcreteEntity")
public class ConcreteEntity extends BaseLongIdEntity {
// lots of POD properties
}
EntityAccessGroup
@Entity(name = "app$EntityAccessGroup")
public class EntityAccessGroup extends Group {
@OnDeleteInverse(DeletePolicy.CASCADE)
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "CONCRETE_ENTITY_ID")
private ConcreteEntity concreteEntity;
// getters, setters
}
ConcreteEntityListener
@Component("app_ConcreteEntityListener")
public class ConcreteEntityListener implements BeforeInsertEntityListener<ConcreteEntity> {
@Inject private Metadata metadata;
@Override
public void onBeforeInsert(ConcreteEntity entity, EntityManager entityManager) {
Group parentGroup = entityManager
.createQuery("SELECT g FROM sec$Group g WHERE g.name = :name", Group.class)
.setParameter("name", "parentAccessGroupName")
.getFirstResult();
if (parentGroup == null) {
throw new IllegalStateException("Parent access group missing!");
}
EntityAccessGroup accessGroup = metadata.create(EntityAccessGroup.class);
accessGroup.setParent(parentGroup);
accessGroup.setConcreteEntity(entity);
accessGroup.setName(generateAccessGroupName(entity)); // returns a string based on entity.getName()
entityManager.persist(accessGroup);
SessionAttribute attr = metadata.create(SessionAttribute.class);
attr.setGroup(accessGroup);
attr.setName("concreteEntityId");
attr.setDatatype("long");
attr.setStringValue(entity.getId().toString());
entityManager.persist(attr);
}
}
So when I create a new ConcreteEntity, I also get a new EntityAccessGroup set up which puts the ConcreteEntity ID into the session.
However, if I introduce a superclass to pull out some of the implementation of ConcreteEntity, things no longer work correctly. For example, if I add:
MyBaseEntity
@DiscriminatorColumn(name = "DTYPE", discriminatorType = DiscriminatorType.STRING)
@Inheritance(strategy = InheritanceType.JOINED)
@Table(name = "APP_MY_BASE_ENTITY")
@Entity(name = "app$MyBaseEntity")
public class MyBaseEntity extends BaseLongIdEntity implements SoftDelete, Updatable, Creatable {
// some common stuff
}
Then change ConcreteEntity thus:
@PrimaryKeyJoinColumn(name = "ID", referencedColumnName = "ID")
@Listeners("app_ConcreteEntityListener")
@Table(name = "APP_CONCRETE_ENTITY")
@Entity(name = "app$ConcreteEntity")
public class ConcreteEntity extends MyBaseEntity {
// Some concrete class-specific stuff
}
Now I get the following SQLException when I try to insert a new ConcreteEntity (caused by the underlying INSERT INTO SEC_GROUP … query):
SQLException: The INSERT statement conflicted with the FOREIGN KEY constraint “FK_SEC_GROUP_CONCRETE_ENTITY”. The conflict occurred in database “mydbname”, table “dbo.AAP_CONCRETE_ENTITY”, column ‘ID’.