HHH-4694:
- if a field is non-insertable in a "fake" bidirectional relation, not storing modifications made on the non-insertable side - also, not generating bidirectional collection changes in such case - updating test git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@18226 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
3740a20550
commit
ad0be2d822
|
@ -224,7 +224,7 @@ public final class CollectionMetadataGenerator {
|
|||
// The mapper will only be used to map from entity to map, so no need to provide other details
|
||||
// when constructing the PropertyData.
|
||||
new PropertyData(auditMappedBy, null, null, null),
|
||||
referencedEntityName);
|
||||
referencedEntityName, false);
|
||||
} else {
|
||||
fakeBidirectionalRelationMapper = null;
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ public final class ToOneRelationMetadataGenerator {
|
|||
|
||||
// Storing information about this relation
|
||||
mainGenerator.getEntitiesConfigurations().get(entityName).addToOneRelation(
|
||||
propertyAuditingData.getName(), referencedEntityName, relMapper);
|
||||
propertyAuditingData.getName(), referencedEntityName, relMapper, insertable);
|
||||
|
||||
// If the property isn't insertable, checking if this is not a "fake" bidirectional many-to-one relationship,
|
||||
// that is, when the one side owns the relation (and is a collection), and the many side is non insertable.
|
||||
|
@ -79,6 +79,7 @@ public final class ToOneRelationMetadataGenerator {
|
|||
// the entity that didn't involve the relation, it's value will then be stored properly. In case of changes
|
||||
// to the entity that did involve the relation, it's the responsibility of the collection side to store the
|
||||
// proper data.
|
||||
boolean nonInsertableFake = false;
|
||||
if (!insertable) {
|
||||
ClassAuditingData referencedAuditingData = mainGenerator.getClassesAuditingData().getClassAuditingData(referencedEntityName);
|
||||
|
||||
|
@ -91,6 +92,7 @@ public final class ToOneRelationMetadataGenerator {
|
|||
referencedEntityName + " entity.");
|
||||
|
||||
insertable = true;
|
||||
nonInsertableFake = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -106,7 +108,7 @@ public final class ToOneRelationMetadataGenerator {
|
|||
|
||||
// Adding mapper for the id
|
||||
PropertyData propertyData = propertyAuditingData.getPropertyData();
|
||||
mapper.addComposite(propertyData, new ToOneIdMapper(relMapper, propertyData, referencedEntityName));
|
||||
mapper.addComposite(propertyData, new ToOneIdMapper(relMapper, propertyData, referencedEntityName, nonInsertableFake));
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
|
|
|
@ -51,31 +51,31 @@ public class EntityConfiguration {
|
|||
this.relations = new HashMap<String, RelationDescription>();
|
||||
}
|
||||
|
||||
public void addToOneRelation(String fromPropertyName, String toEntityName, IdMapper idMapper) {
|
||||
public void addToOneRelation(String fromPropertyName, String toEntityName, IdMapper idMapper, boolean insertable) {
|
||||
relations.put(fromPropertyName, new RelationDescription(fromPropertyName, RelationType.TO_ONE,
|
||||
toEntityName, null, idMapper, null));
|
||||
toEntityName, null, idMapper, null, insertable));
|
||||
}
|
||||
|
||||
public void addToOneNotOwningRelation(String fromPropertyName, String mappedByPropertyName, String toEntityName,
|
||||
IdMapper idMapper) {
|
||||
relations.put(fromPropertyName, new RelationDescription(fromPropertyName, RelationType.TO_ONE_NOT_OWNING,
|
||||
toEntityName, mappedByPropertyName, idMapper, null));
|
||||
toEntityName, mappedByPropertyName, idMapper, null, true));
|
||||
}
|
||||
|
||||
public void addToManyNotOwningRelation(String fromPropertyName, String mappedByPropertyName, String toEntityName,
|
||||
IdMapper idMapper, PropertyMapper fakeBidirectionalRelationMapper) {
|
||||
relations.put(fromPropertyName, new RelationDescription(fromPropertyName, RelationType.TO_MANY_NOT_OWNING,
|
||||
toEntityName, mappedByPropertyName, idMapper, fakeBidirectionalRelationMapper));
|
||||
toEntityName, mappedByPropertyName, idMapper, fakeBidirectionalRelationMapper, true));
|
||||
}
|
||||
|
||||
public void addToManyMiddleRelation(String fromPropertyName, String toEntityName) {
|
||||
relations.put(fromPropertyName, new RelationDescription(fromPropertyName, RelationType.TO_MANY_MIDDLE,
|
||||
toEntityName, null, null, null));
|
||||
toEntityName, null, null, null, true));
|
||||
}
|
||||
|
||||
public void addToManyMiddleNotOwningRelation(String fromPropertyName, String mappedByPropertyName, String toEntityName) {
|
||||
relations.put(fromPropertyName, new RelationDescription(fromPropertyName, RelationType.TO_MANY_MIDDLE_NOT_OWNING,
|
||||
toEntityName, mappedByPropertyName, null, null));
|
||||
toEntityName, mappedByPropertyName, null, null, true));
|
||||
}
|
||||
|
||||
public boolean isRelation(String propertyName) {
|
||||
|
|
|
@ -36,17 +36,19 @@ public class RelationDescription {
|
|||
private final String mappedByPropertyName;
|
||||
private final IdMapper idMapper;
|
||||
private final PropertyMapper fakeBidirectionalRelationMapper;
|
||||
private final boolean insertable;
|
||||
private boolean bidirectional;
|
||||
|
||||
public RelationDescription(String fromPropertyName, RelationType relationType, String toEntityName,
|
||||
String mappedByPropertyName, IdMapper idMapper,
|
||||
PropertyMapper fakeBidirectionalRelationMapper) {
|
||||
PropertyMapper fakeBidirectionalRelationMapper, boolean insertable) {
|
||||
this.fromPropertyName = fromPropertyName;
|
||||
this.relationType = relationType;
|
||||
this.toEntityName = toEntityName;
|
||||
this.mappedByPropertyName = mappedByPropertyName;
|
||||
this.idMapper = idMapper;
|
||||
this.fakeBidirectionalRelationMapper = fakeBidirectionalRelationMapper;
|
||||
this.insertable = insertable;
|
||||
|
||||
this.bidirectional = false;
|
||||
}
|
||||
|
@ -75,6 +77,10 @@ public class RelationDescription {
|
|||
return fakeBidirectionalRelationMapper;
|
||||
}
|
||||
|
||||
public boolean isInsertable() {
|
||||
return insertable;
|
||||
}
|
||||
|
||||
public boolean isBidirectional() {
|
||||
return bidirectional;
|
||||
}
|
||||
|
|
|
@ -49,20 +49,26 @@ public class ToOneIdMapper implements PropertyMapper {
|
|||
private final IdMapper delegate;
|
||||
private final PropertyData propertyData;
|
||||
private final String referencedEntityName;
|
||||
private final boolean nonInsertableFake;
|
||||
|
||||
public ToOneIdMapper(IdMapper delegate, PropertyData propertyData, String referencedEntityName) {
|
||||
public ToOneIdMapper(IdMapper delegate, PropertyData propertyData, String referencedEntityName, boolean nonInsertableFake) {
|
||||
this.delegate = delegate;
|
||||
this.propertyData = propertyData;
|
||||
this.referencedEntityName = referencedEntityName;
|
||||
this.nonInsertableFake = nonInsertableFake;
|
||||
}
|
||||
|
||||
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
|
||||
HashMap<String, Object> newData = new HashMap<String, Object>();
|
||||
data.put(propertyData.getName(), newData);
|
||||
|
||||
delegate.mapToMapFromEntity(newData, newObj);
|
||||
// If this property is originally non-insertable, but made insertable because it is in a many-to-one "fake"
|
||||
// bi-directional relation, we always store the "old", unchaged data, to prevent storing changes made
|
||||
// to this field. It is the responsibility of the collection to properly update it if it really changed.
|
||||
delegate.mapToMapFromEntity(newData, nonInsertableFake ? oldObj : newObj);
|
||||
|
||||
return !Tools.entitiesEqual(session, newObj, oldObj);
|
||||
//noinspection SimplifiableConditionalExpression
|
||||
return nonInsertableFake ? false : !Tools.entitiesEqual(session, newObj, oldObj);
|
||||
}
|
||||
|
||||
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
||||
|
|
|
@ -84,7 +84,8 @@ public class AuditEventListener implements PostInsertEventListener, PostUpdateEv
|
|||
for (int i=0; i<propertyNames.length; i++) {
|
||||
String propertyName = propertyNames[i];
|
||||
RelationDescription relDesc = verCfg.getEntCfg().getRelationDescription(entityName, propertyName);
|
||||
if (relDesc != null && relDesc.isBidirectional() && relDesc.getRelationType() == RelationType.TO_ONE) {
|
||||
if (relDesc != null && relDesc.isBidirectional() && relDesc.getRelationType() == RelationType.TO_ONE &&
|
||||
relDesc.isInsertable()) {
|
||||
// Checking for changes
|
||||
Object oldValue = oldState == null ? null : oldState[i];
|
||||
Object newValue = newState == null ? null : newState[i];
|
||||
|
@ -144,13 +145,16 @@ public class AuditEventListener implements PostInsertEventListener, PostUpdateEv
|
|||
if (verCfg.getEntCfg().isVersioned(entityName)) {
|
||||
AuditSync verSync = verCfg.getSyncManager().get(event.getSession());
|
||||
|
||||
verSync.addWorkUnit(new AddWorkUnit(event.getSession(), event.getPersister().getEntityName(), verCfg,
|
||||
event.getId(), event.getPersister(), event.getState()));
|
||||
AuditWorkUnit workUnit = new AddWorkUnit(event.getSession(), event.getPersister().getEntityName(), verCfg,
|
||||
event.getId(), event.getPersister(), event.getState());
|
||||
verSync.addWorkUnit(workUnit);
|
||||
|
||||
if (workUnit.containsWork()) {
|
||||
generateBidirectionalCollectionChangeWorkUnits(verSync, event.getPersister(), entityName, event.getState(),
|
||||
null, event.getSession());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onPostUpdate(PostUpdateEvent event) {
|
||||
String entityName = event.getPersister().getEntityName();
|
||||
|
@ -158,13 +162,16 @@ public class AuditEventListener implements PostInsertEventListener, PostUpdateEv
|
|||
if (verCfg.getEntCfg().isVersioned(entityName)) {
|
||||
AuditSync verSync = verCfg.getSyncManager().get(event.getSession());
|
||||
|
||||
verSync.addWorkUnit(new ModWorkUnit(event.getSession(), event.getPersister().getEntityName(), verCfg,
|
||||
event.getId(), event.getPersister(), event.getState(), event.getOldState()));
|
||||
AuditWorkUnit workUnit = new ModWorkUnit(event.getSession(), event.getPersister().getEntityName(), verCfg,
|
||||
event.getId(), event.getPersister(), event.getState(), event.getOldState());
|
||||
verSync.addWorkUnit(workUnit);
|
||||
|
||||
if (workUnit.containsWork()) {
|
||||
generateBidirectionalCollectionChangeWorkUnits(verSync, event.getPersister(), entityName, event.getState(),
|
||||
event.getOldState(), event.getSession());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onPostDelete(PostDeleteEvent event) {
|
||||
String entityName = event.getPersister().getEntityName();
|
||||
|
@ -172,13 +179,16 @@ public class AuditEventListener implements PostInsertEventListener, PostUpdateEv
|
|||
if (verCfg.getEntCfg().isVersioned(entityName)) {
|
||||
AuditSync verSync = verCfg.getSyncManager().get(event.getSession());
|
||||
|
||||
verSync.addWorkUnit(new DelWorkUnit(event.getSession(), event.getPersister().getEntityName(), verCfg,
|
||||
event.getId(), event.getPersister(), event.getDeletedState()));
|
||||
AuditWorkUnit workUnit = new DelWorkUnit(event.getSession(), event.getPersister().getEntityName(), verCfg,
|
||||
event.getId(), event.getPersister(), event.getDeletedState());
|
||||
verSync.addWorkUnit(workUnit);
|
||||
|
||||
if (workUnit.containsWork()) {
|
||||
generateBidirectionalCollectionChangeWorkUnits(verSync, event.getPersister(), entityName, null,
|
||||
event.getDeletedState(), event.getSession());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void generateBidirectionalCollectionChangeWorkUnits(AuditSync verSync, AbstractCollectionEvent event,
|
||||
PersistentCollectionChangeWorkUnit workUnit,
|
||||
|
|
|
@ -86,12 +86,27 @@ public class JoinColumnBidirectionalList extends AbstractEntityTest {
|
|||
em.getTransaction().commit();
|
||||
em.clear();
|
||||
|
||||
// No revision - no changes
|
||||
em.getTransaction().begin();
|
||||
|
||||
ing1 = em.find(ListJoinColumnBidirectionalRefIngEntity.class, ing1.getId());
|
||||
ing2 = em.find(ListJoinColumnBidirectionalRefIngEntity.class, ing2.getId());
|
||||
ed1 = em.find(ListJoinColumnBidirectionalRefEdEntity.class, ed1.getId());
|
||||
ed2 = em.find(ListJoinColumnBidirectionalRefEdEntity.class, ed2.getId());
|
||||
|
||||
ed2.setOwner(ing2);
|
||||
|
||||
em.getTransaction().commit();
|
||||
em.clear();
|
||||
|
||||
// Revision 3 (ing1: ed1, ed2)
|
||||
em.getTransaction().begin();
|
||||
|
||||
ed1 = em.find(ListJoinColumnBidirectionalRefEdEntity.class, ed1.getId());
|
||||
|
||||
ed1.setData("ed1 bis");
|
||||
// Shouldn't get written
|
||||
ed1.setOwner(ing2);
|
||||
|
||||
em.getTransaction().commit();
|
||||
em.clear();
|
||||
|
|
Loading…
Reference in New Issue