use of com.blazebit.persistence.view.impl.collection.RecordingList in project blaze-persistence by Blazebit.
the class EntityViewUpdaterImpl method createPluralAttributeFlusher.
private DirtyAttributeFlusher<?, ?, ?> createPluralAttributeFlusher(EntityViewManagerImpl evm, Map<Object, EntityViewUpdaterImpl> localCache, ManagedViewTypeImplementor<?> viewType, String idAttributeName, FlushStrategy flushStrategy, AbstractMethodAttribute<?, ?> attribute, DirtyAttributeFlusher<?, ?, ?> ownerIdFlusher, EntityViewUpdaterImpl owner, String ownerMapping) {
EntityMetamodel entityMetamodel = evm.getMetamodel().getEntityMetamodel();
Class<?> entityClass = viewType.getEntityClass();
ExtendedManagedType managedType = entityMetamodel.getManagedType(ExtendedManagedType.class, entityClass);
String attributeName = attribute.getName();
String attributeMapping = attribute.getMapping();
AttributeAccessor entityAttributeAccessor = Accessors.forEntityMapping(evm, attribute);
boolean cascadeDelete = attribute.isDeleteCascaded();
boolean viewOnlyDeleteCascaded = cascadeDelete && !managedType.getAttribute(attributeMapping).isDeleteCascaded();
boolean optimisticLockProtected = attribute.isOptimisticLockProtected();
JpaProvider jpaProvider = evm.getJpaProvider();
PluralAttribute<?, ?, ?> pluralAttribute = (PluralAttribute<?, ?, ?>) attribute;
InitialValueAttributeAccessor viewAttributeAccessor = Accessors.forMutableViewAttribute(evm, attribute);
ManagedType<?> ownerManagedType = owner == null ? viewType.getJpaManagedType() : owner.managedViewType.getJpaManagedType();
EntityType<?> ownerEntityType = ownerManagedType instanceof EntityType<?> ? (EntityType<?>) ownerManagedType : null;
DirtyAttributeFlusher<?, ?, ?> attributeOwnerFlusher;
if (attributeMapping == null || ownerEntityType == null) {
// In case of cascading only attributes i.e. correlations, we use the owner id flusher as it's not updatable anyway
attributeOwnerFlusher = ownerIdFlusher;
} else {
Map<String, String> joinTableOwnerProperties;
if (ownerMapping == null) {
joinTableOwnerProperties = jpaProvider.getJoinMappingPropertyNames(ownerEntityType, ownerMapping, attributeMapping);
} else {
joinTableOwnerProperties = jpaProvider.getJoinMappingPropertyNames(ownerEntityType, ownerMapping, ownerMapping + "." + attributeMapping);
}
if (joinTableOwnerProperties.size() != 1) {
String idMapping = ownerIdFlusher.getMapping();
String prefix;
if (idMapping.endsWith(".")) {
prefix = idMapping;
} else {
prefix = idMapping + ".";
}
for (String joinTableOwnerProperty : joinTableOwnerProperties.keySet()) {
if (!joinTableOwnerProperty.startsWith(prefix)) {
throw new IllegalArgumentException("Multiple joinable owner properties for attribute '" + attributeName + "' of " + ownerEntityType.getJavaType().getName() + " found which is not yet supported. Consider using the primary key instead!");
}
}
attributeOwnerFlusher = ownerIdFlusher;
} else if (ownerIdFlusher.getMapping().equals(joinTableOwnerProperties.values().iterator().next())) {
attributeOwnerFlusher = ownerIdFlusher;
} else {
attributeOwnerFlusher = findSingularAttributeFlusherByMapping(evm, localCache, owner, viewType, attributeName, joinTableOwnerProperties.keySet().iterator().next());
}
}
TypeDescriptor elementDescriptor = TypeDescriptor.forType(evm, localCache, this, attribute, pluralAttribute.getElementType(), owner, ownerMapping);
boolean collectionUpdatable = attribute.isUpdatable();
CollectionRemoveListener elementRemoveListener = createOrphanRemoveListener(attribute, elementDescriptor);
CollectionRemoveListener elementCascadeDeleteListener = createCascadeDeleteListener(attribute, elementDescriptor);
boolean jpaProviderDeletesCollection;
boolean supportsCollectionDml = jpaProvider.supportsInsertStatement();
if (elementDescriptor.getAttributeIdAttributeName() != null) {
jpaProviderDeletesCollection = jpaProvider.supportsJoinTableCleanupOnDelete();
} else {
jpaProviderDeletesCollection = jpaProvider.supportsCollectionTableCleanupOnDelete();
}
if (attribute instanceof MapAttribute<?, ?, ?>) {
MapAttribute<?, ?, ?> mapAttribute = (MapAttribute<?, ?, ?>) attribute;
TypeDescriptor keyDescriptor = TypeDescriptor.forType(evm, localCache, this, attribute, mapAttribute.getKeyType(), owner, ownerMapping);
// TODO: currently there is no possibility to set this
CollectionRemoveListener keyRemoveListener = null;
CollectionRemoveListener keyCascadeDeleteListener = null;
if (collectionUpdatable || keyDescriptor.shouldFlushMutations() || elementDescriptor.shouldFlushMutations() || shouldPassThrough(evm, viewType, attribute)) {
MapViewToEntityMapper mapper = new SimpleMapViewToEntityMapper(keyDescriptor.getViewToEntityMapper(), elementDescriptor.getViewToEntityMapper());
MapViewToEntityMapper loadOnlyMapper = new SimpleMapViewToEntityMapper(keyDescriptor.getLoadOnlyViewToEntityMapper(), elementDescriptor.getLoadOnlyViewToEntityMapper());
MapInstantiatorImplementor<?, ?> mapInstantiator = attribute.getMapInstantiator();
return new MapAttributeFlusher<Object, RecordingMap<Map<?, ?>, ?, ?>>(attributeName, attributeMapping, owner == null ? entityClass : owner.fullEntityLoader.getEntityClass(), idAttributeName, ownerMapping, attributeOwnerFlusher, createPluralAttributeSubFlusher(evm, localCache, viewType, attribute, "element", mapAttribute.getElementType(), owner, ownerMapping), supportsCollectionDml, flushStrategy, entityAttributeAccessor, viewAttributeAccessor, optimisticLockProtected, collectionUpdatable, keyCascadeDeleteListener, elementCascadeDeleteListener, keyRemoveListener, elementRemoveListener, viewOnlyDeleteCascaded, jpaProviderDeletesCollection, keyDescriptor, elementDescriptor, mapper, loadOnlyMapper, mapInstantiator);
} else {
return null;
}
} else {
if (collectionUpdatable || elementDescriptor.shouldFlushMutations() || shouldPassThrough(evm, viewType, attribute)) {
InverseFlusher<Object> inverseFlusher = InverseFlusher.forAttribute(evm, localCache, viewType, attribute, elementDescriptor, owner, ownerMapping);
InverseRemoveStrategy inverseRemoveStrategy = attribute.getInverseRemoveStrategy();
CollectionInstantiatorImplementor<?, ?> collectionInstantiator = attribute.getCollectionInstantiator();
if (pluralAttribute.isIndexed()) {
return new IndexedListAttributeFlusher<Object, RecordingList<List<?>>>(attributeName, attributeMapping, owner == null ? entityClass : owner.fullEntityLoader.getEntityClass(), idAttributeName, ownerMapping, attributeOwnerFlusher, createPluralAttributeSubFlusher(evm, localCache, viewType, attribute, "element", pluralAttribute.getElementType(), owner, ownerMapping), supportsCollectionDml, flushStrategy, entityAttributeAccessor, viewAttributeAccessor, optimisticLockProtected, collectionUpdatable, viewOnlyDeleteCascaded, jpaProviderDeletesCollection, elementCascadeDeleteListener, elementRemoveListener, collectionInstantiator, elementDescriptor, inverseFlusher, inverseRemoveStrategy);
} else {
return new CollectionAttributeFlusher(attributeName, attributeMapping, owner == null ? entityClass : owner.fullEntityLoader.getEntityClass(), idAttributeName, ownerMapping, attributeOwnerFlusher, createPluralAttributeSubFlusher(evm, localCache, viewType, attribute, "element", pluralAttribute.getElementType(), owner, ownerMapping), supportsCollectionDml, flushStrategy, entityAttributeAccessor, viewAttributeAccessor, optimisticLockProtected, collectionUpdatable, viewOnlyDeleteCascaded, jpaProviderDeletesCollection, elementCascadeDeleteListener, elementRemoveListener, collectionInstantiator, elementDescriptor, inverseFlusher, inverseRemoveStrategy);
}
} else {
return null;
}
}
}
use of com.blazebit.persistence.view.impl.collection.RecordingList in project blaze-persistence by Blazebit.
the class IndexedListAttributeFlusher method getDirtyKind.
@Override
public DirtyKind getDirtyKind(V initial, V current) {
if (current == null) {
if (initial == null) {
return DirtyKind.NONE;
}
return DirtyKind.UPDATED;
}
if (initial == null) {
return DirtyKind.UPDATED;
}
if (initial == current) {
if (current instanceof RecordingList<?>) {
return super.getDirtyKind(initial, current);
}
} else {
if (initial.size() != current.size()) {
return DirtyKind.MUTATED;
}
if (elementDescriptor.shouldFlushMutations()) {
if (elementDescriptor.supportsDirtyCheck()) {
if (elementDescriptor.isSubview()) {
ViewToEntityMapper mapper = elementDescriptor.getViewToEntityMapper();
for (int i = 0; i < current.size(); i++) {
Object o = current.get(i);
if (!Objects.equals(initial.get(i), o)) {
return DirtyKind.MUTATED;
}
if (o instanceof DirtyStateTrackable) {
DirtyStateTrackable element = (DirtyStateTrackable) o;
if (mapper.getUpdater(o).getDirtyChecker().getDirtyKind(element, element) != DirtyKind.NONE) {
return DirtyKind.MUTATED;
}
}
}
} else {
BasicUserType<Object> userType = elementDescriptor.getBasicUserType();
for (int i = 0; i < current.size(); i++) {
Object o = current.get(i);
if (!Objects.equals(initial.get(i), o)) {
return DirtyKind.MUTATED;
}
String[] dirtyProperties = userType.getDirtyProperties(o);
if (dirtyProperties != null) {
return DirtyKind.MUTATED;
}
}
}
} else {
if (elementDescriptor.getBasicUserType().supportsDeepCloning()) {
return collectionEquals(initial, current) ? DirtyKind.NONE : DirtyKind.MUTATED;
} else {
// If we don't support dirty checking we always have to assume dirtyness
return DirtyKind.MUTATED;
}
}
} else {
return collectionEquals(initial, current) ? DirtyKind.NONE : DirtyKind.MUTATED;
}
}
return DirtyKind.NONE;
}
Aggregations