use of com.blazebit.persistence.view.impl.entity.ViewToEntityMapper in project blaze-persistence by Blazebit.
the class MapAttributeFlusher method mergeCollectionElements.
@Override
protected boolean mergeCollectionElements(UpdateContext context, Object ownerView, Object view, E entity, V value) {
if (elementFlushers != null) {
if (flushStrategy == FlushStrategy.ENTITY || context.isForceEntity()) {
for (CollectionElementAttributeFlusher<E, V> elementFlusher : elementFlushers) {
elementFlusher.flushEntity(context, entity, ownerView, view, value, null);
}
} else {
for (CollectionElementAttributeFlusher<E, V> elementFlusher : elementFlushers) {
elementFlusher.flushQuery(context, null, null, null, ownerView, view, value, null, null);
}
}
return !elementFlushers.isEmpty();
} else {
// Invocations of JPA merge can change the identity that leads to requeuing into the collection being required
final boolean needsRequeuing = keyDescriptor.shouldJpaMerge() || value instanceof RecordingMap<?, ?, ?> && elementDescriptor.shouldJpaMerge();
if (needsRequeuing) {
if (value instanceof RecordingMap<?, ?, ?>) {
return mergeAndRequeue(context, (RecordingMap) value, ((RecordingMap) value).getDelegate());
} else {
return mergeAndRequeue(context, null, (Map<Object, Object>) (Map<?, ?>) value);
}
} else {
@SuppressWarnings("unchecked") final EntityManager em = context.getEntityManager();
final ViewToEntityMapper keyMapper = mapper.getKeyMapper();
final ViewToEntityMapper valueMapper = mapper.getValueMapper();
final boolean flushKey = keyDescriptor.shouldJpaPersistOrMerge();
final boolean flushValue = elementDescriptor.shouldJpaPersistOrMerge();
final Iterator<Map.Entry<Object, Object>> iter = getRecordingIterator(value);
try {
while (iter.hasNext()) {
Map.Entry<Object, Object> entry = iter.next();
Object k = entry.getKey();
Object v = entry.getValue();
if (flushKey) {
persistOrMergeKey(context, em, k);
} else if (keyMapper != null) {
keyMapper.applyToEntity(context, null, k);
}
if (v != null) {
if (flushValue) {
v = persistOrMerge(em, v);
} else if (valueMapper != null) {
valueMapper.applyToEntity(context, null, v);
}
}
if (v != entry.getValue()) {
entry.setValue(v);
}
}
} finally {
resetRecordingIterator(value);
}
return true;
}
}
}
use of com.blazebit.persistence.view.impl.entity.ViewToEntityMapper in project blaze-persistence by Blazebit.
the class MapAttributeFlusher method replaceCollection.
@Override
protected void replaceCollection(UpdateContext context, Object ownerView, Object view, E entity, V value, FlushStrategy flushStrategy) {
if (flushStrategy == FlushStrategy.QUERY) {
Map<Object, Object> removedAllObjects;
if (deleteElements(context, ownerView, view, value, false, null, true)) {
// TODO: We should load the initial value
removedAllObjects = Collections.emptyMap();
} else {
removedAllObjects = Collections.emptyMap();
}
addElements(context, ownerView, view, removedAllObjects, true, value, null, null, true);
processRemovedObjects(context, removedAllObjects);
} else {
if (entityAttributeAccessor != null) {
if (keyDescriptor.isSubview() || elementDescriptor.isSubview()) {
Map<Object, Object> newMap;
if (value == null) {
newMap = (Map<Object, Object>) createJpaMap(0);
} else {
newMap = (Map<Object, Object>) createJpaMap(value.size());
ViewToEntityMapper keyMapper = mapper.getKeyMapper();
ViewToEntityMapper valueMapper = mapper.getValueMapper();
final Iterator<Map.Entry<Object, Object>> iter = getRecordingIterator(value);
try {
while (iter.hasNext()) {
Map.Entry<Object, Object> entry = iter.next();
Object k = entry.getKey();
Object v = entry.getValue();
if (keyMapper != null) {
k = keyMapper.applyToEntity(context, null, k);
}
if (valueMapper != null) {
v = valueMapper.applyToEntity(context, null, v);
}
newMap.put(k, v);
}
} finally {
resetRecordingIterator(value);
}
}
entityAttributeAccessor.setValue(entity, newMap);
} else {
entityAttributeAccessor.setValue(entity, value);
}
}
}
}
use of com.blazebit.persistence.view.impl.entity.ViewToEntityMapper in project blaze-persistence by Blazebit.
the class MapAttributeFlusher method addFlatViewElementFlushActions.
@Override
protected void addFlatViewElementFlushActions(UpdateContext context, TypeDescriptor typeDescriptor, List<MapAction<?>> actions, V current) {
final ViewToEntityMapper mapper = typeDescriptor.getViewToEntityMapper();
for (Map.Entry<?, ?> entry : current.entrySet()) {
Object o = entry.getValue();
if (o instanceof MutableStateTrackable) {
MutableStateTrackable element = (MutableStateTrackable) o;
@SuppressWarnings("unchecked") DirtyAttributeFlusher<?, E, V> flusher = (DirtyAttributeFlusher<?, E, V>) (DirtyAttributeFlusher) mapper.getNestedDirtyFlusher(context, element, (DirtyAttributeFlusher) null);
if (flusher != null) {
// At this point, we have to check the collection actions to determine if the element was added through actions somehow
// We will register a special MapPutAction if the element was not added through actions to issue an UPDATE statement
// By default, since the element is dirty, we start with the state UPDATED and go through state transitions
// based on the containment of the element in the added/removed objects collections of the actions
EntryState state = EntryState.UPDATED;
Object replacedObject = element;
for (MapAction<?> action : actions) {
Collection<Object> removedElements = action.getRemovedElements();
Collection<Object> addedElements = action.getAddedElements();
if (removedElements.isEmpty()) {
if (identityContains(addedElements, element)) {
state = state.onAdd();
}
} else if (addedElements.isEmpty()) {
if (identityContains(removedElements, element)) {
state = state.onRemove();
}
} else {
// Here we have a MapPutAction or MapPutAllAction where added/removed have the same cardinality
Iterator<Object> addedIter = addedElements.iterator();
Iterator<Object> removedIter = removedElements.iterator();
while (addedIter.hasNext()) {
Object added = addedIter.next();
Object removed = removedIter.next();
if (removed == element) {
if (added == element) {
// This is a MapPutAction or MapPutAllAction where the old and new object are the same instances
replacedObject = element;
state = EntryState.UPDATED;
} else {
state = state.onRemove();
}
break;
} else if (added == element) {
replacedObject = removed;
state = EntryState.UPDATED;
break;
}
}
}
}
// and there is no action that would flush the object changes already
if (state == EntryState.UPDATED && replacedObject == element) {
actions.add(new MapPutAction<>(entry.getKey(), element, element));
}
}
}
}
}
use of com.blazebit.persistence.view.impl.entity.ViewToEntityMapper in project blaze-persistence by Blazebit.
the class MapAttributeFlusher method flushCollectionViewElements.
private Map<Object, Object> flushCollectionViewElements(UpdateContext context, V value) {
ViewToEntityMapper keyMapper = mapper.getKeyMapper();
ViewToEntityMapper valueMapper = mapper.getValueMapper();
final Iterator<Map.Entry<Object, Object>> iter = getRecordingIterator(value);
Map<Object, Object> embeddables = null;
if ((!keyDescriptor.isIdentifiable() || !elementDescriptor.isIdentifiable()) && mapping != null) {
embeddables = new LinkedHashMap<>();
}
try {
while (iter.hasNext()) {
Map.Entry<Object, Object> entry = iter.next();
Object k = entry.getKey();
Object v = entry.getValue();
Object newKey = k;
if (keyMapper != null) {
newKey = keyMapper.applyToEntity(context, null, k);
}
Object newValue = v;
if (valueMapper != null) {
newValue = valueMapper.applyToEntity(context, null, v);
}
if (embeddables != null) {
// Only query flushing of an element collection can bring us here
embeddables.put(newKey, newValue);
}
}
} finally {
resetRecordingIterator(value);
}
return embeddables;
}
use of com.blazebit.persistence.view.impl.entity.ViewToEntityMapper in project blaze-persistence by Blazebit.
the class TypeDescriptor method forType.
public static TypeDescriptor forType(EntityViewManagerImpl evm, Map<Object, EntityViewUpdaterImpl> localCache, EntityViewUpdaterImpl updater, AbstractMethodAttribute<?, ?> attribute, Type<?> type, EntityViewUpdaterImpl owner, String ownerMapping) {
EntityMetamodel entityMetamodel = evm.getMetamodel().getEntityMetamodel();
String attributeLocation = attribute.getLocation();
boolean cascadePersist = attribute.isPersistCascaded();
boolean cascadeUpdate = attribute.isUpdateCascaded();
Set<Type<?>> readOnlyAllowedSubtypes = attribute.getReadOnlyAllowedSubtypes();
Set<Type<?>> persistAllowedSubtypes = attribute.getPersistCascadeAllowedSubtypes();
Set<Type<?>> updateAllowedSubtypes = attribute.getUpdateCascadeAllowedSubtypes();
EntityToEntityMapper entityToEntityMapper = null;
ViewToEntityMapper viewToEntityMapper = null;
ViewToEntityMapper loadOnlyViewToEntityMapper = null;
final ManagedType<?> managedType = entityMetamodel.getManagedType(type.getJavaType());
final boolean jpaEntity = managedType instanceof EntityType<?>;
final boolean jpaManaged = managedType != null;
final boolean mutable;
final boolean identifiable;
TypeConverter<Object, Object> converter = (TypeConverter<Object, Object>) type.getConverter();
BasicUserType<Object> basicUserType;
ManagedType<?> ownerEntityType = owner == null ? attribute.getDeclaringType().getJpaManagedType() : owner.getManagedViewType().getJpaManagedType();
String attributeIdAttributeName = null;
String entityIdAttributeName = null;
Class<?> jpaType;
// TODO: currently we only check if the declared type is mutable, but we have to let the collection flusher which types are considered updatable/creatable
if (type instanceof BasicType<?>) {
jpaType = type.getJavaType();
basicUserType = (BasicUserType<Object>) ((BasicType<?>) type).getUserType();
mutable = basicUserType.isMutable();
identifiable = jpaEntity || !jpaManaged;
if (jpaEntity) {
Map<String, Map<?, ?>> fetchGraph = null;
UnmappedAttributeCascadeDeleter deleter = null;
// We only need to know the fetch graph when we actually do updates
if (cascadeUpdate) {
fetchGraph = getFetchGraph(attribute.getFetches(), attribute.getMapping(), managedType);
}
if (ownerEntityType instanceof EntityType<?>) {
ExtendedManagedType<?> extendedManagedType = evm.getMetamodel().getEntityMetamodel().getManagedType(ExtendedManagedType.class, type.getJavaType());
entityIdAttributeName = extendedManagedType.getIdAttribute().getName();
attributeIdAttributeName = getAttributeElementIdentifier(evm, (EntityType<?>) ownerEntityType, attribute.getName(), ownerMapping, attribute.getMapping(), extendedManagedType.getType());
// Only construct when orphanRemoval or delete cascading is enabled, orphanRemoval implies delete cascading
if (attribute.isDeleteCascaded()) {
String mapping = attribute.getMapping();
ExtendedManagedType elementManagedType = entityMetamodel.getManagedType(ExtendedManagedType.class, attribute.getDeclaringType().getJpaManagedType());
deleter = new UnmappedBasicAttributeCascadeDeleter(evm, mapping, elementManagedType.getAttribute(mapping), mapping + "." + attributeIdAttributeName, false);
}
}
// TODO: EntityToEntityMapper should also use the attributeIdAttributeName
entityToEntityMapper = new DefaultEntityToEntityMapper(cascadePersist, cascadeUpdate, jpaType, basicUserType, new DefaultEntityLoaderFetchGraphNode(evm, attribute.getName(), (EntityType<?>) managedType, fetchGraph), deleter);
}
} else {
ManagedViewTypeImplementor<?> elementType = (ManagedViewTypeImplementor<?>) type;
jpaType = elementType.getEntityClass();
basicUserType = null;
mutable = elementType.isUpdatable() || elementType.isCreatable() || !persistAllowedSubtypes.isEmpty() || !updateAllowedSubtypes.isEmpty();
Set<ManagedViewType<?>> viewTypes = attribute.getViewTypes();
if (elementType.getJpaManagedType() instanceof EntityType<?> && ownerEntityType instanceof EntityType<?>) {
ExtendedManagedType<?> extendedManagedType = evm.getMetamodel().getEntityMetamodel().getManagedType(ExtendedManagedType.class, elementType.getEntityClass());
entityIdAttributeName = extendedManagedType.getIdAttribute().getName();
attributeIdAttributeName = getAttributeElementIdentifier(evm, (EntityType<?>) ownerEntityType, attribute.getName(), ownerMapping, attribute.getMapping(), extendedManagedType.getType());
}
viewToEntityMapper = createViewToEntityMapper(evm, localCache, updater, attributeIdAttributeName, attribute.getMapping(), attributeLocation, elementType, cascadePersist, cascadeUpdate, readOnlyAllowedSubtypes, persistAllowedSubtypes, updateAllowedSubtypes, EntityLoaders.referenceLoaderForAttribute(evm, localCache, elementType, viewTypes, attributeIdAttributeName), owner, ownerMapping);
loadOnlyViewToEntityMapper = createLoadOnlyViewToEntityMapper(attributeLocation, evm, localCache, attributeIdAttributeName, attribute.getMapping(), elementType, cascadePersist, cascadeUpdate, readOnlyAllowedSubtypes, persistAllowedSubtypes, updateAllowedSubtypes, EntityLoaders.referenceLoaderForAttribute(evm, localCache, elementType, viewTypes, attributeIdAttributeName), owner, ownerMapping);
identifiable = viewToEntityMapper.getViewIdAccessor() != null;
}
final boolean shouldJpaMerge = jpaEntity && mutable && cascadeUpdate;
final boolean shouldJpaPersist = jpaEntity && mutable && cascadePersist;
final boolean shouldFlushUpdates = cascadeUpdate && !updateAllowedSubtypes.isEmpty();
final boolean shouldFlushPersists = cascadePersist && !persistAllowedSubtypes.isEmpty();
return new TypeDescriptor(mutable, identifiable, jpaManaged, jpaEntity, shouldJpaMerge, shouldJpaPersist, shouldFlushPersists, shouldFlushUpdates, entityIdAttributeName, attributeIdAttributeName, jpaType, converter, basicUserType, entityToEntityMapper, viewToEntityMapper, loadOnlyViewToEntityMapper);
}
Aggregations