use of com.blazebit.persistence.view.impl.entity.ViewToEntityMapper in project blaze-persistence by Blazebit.
the class CollectionAttributeFlusher method getEntityReferencesForCollectionOperation.
protected List<Object> getEntityReferencesForCollectionOperation(UpdateContext context, Collection<Object> objects) {
List<Object> entityReferences = new ArrayList<>(objects.size());
ViewToEntityMapper loadOnlyViewToEntityMapper = elementDescriptor.getLoadOnlyViewToEntityMapper();
for (Object o : objects) {
if (o != null) {
entityReferences.add(o);
}
}
loadOnlyViewToEntityMapper.applyAll(context, entityReferences);
return entityReferences;
}
use of com.blazebit.persistence.view.impl.entity.ViewToEntityMapper in project blaze-persistence by Blazebit.
the class CollectionAttributeFlusher method replaceCollection.
@Override
protected void replaceCollection(UpdateContext context, Object ownerView, Object view, E entity, V value, FlushStrategy flushStrategy) {
if (flushStrategy == FlushStrategy.QUERY) {
Collection<Object> removedAllObjects;
boolean removedAllWithoutCollectionActions = false;
if (deleteElements(context, ownerView, view, null, value, false, null, true)) {
// TODO: We should load the initial value
removedAllObjects = Collections.emptyList();
removedAllWithoutCollectionActions = true;
} else {
removedAllObjects = Collections.emptyList();
}
addElements(context, ownerView, view, removedAllObjects, true, removedAllWithoutCollectionActions, value, null, null, true);
if (removeListener != null) {
for (Object removedObject : removedAllObjects) {
removeListener.onCollectionRemove(context, removedObject);
}
}
} else {
if (entityAttributeAccessor != null) {
if (elementDescriptor.isSubview()) {
Collection<Object> newCollection;
if (value == null) {
newCollection = (Collection<Object>) createJpaCollection(0);
if (inverseRemoveStrategy == InverseCollectionElementAttributeFlusher.Strategy.REMOVE) {
Collection<Object> oldCollection = (Collection<Object>) entityAttributeAccessor.getValue(entity);
EntityManager entityManager = context.getEntityManager();
for (Object o : oldCollection) {
entityManager.remove(o);
}
}
} else {
newCollection = (Collection<Object>) createJpaCollection(value.size());
final ViewToEntityMapper viewToEntityMapper = elementDescriptor.getViewToEntityMapper();
final Iterator<Object> iter = getRecordingIterator(value);
try {
while (iter.hasNext()) {
Object elem = iter.next();
newCollection.add(viewToEntityMapper.applyToEntity(context, null, elem));
}
} finally {
resetRecordingIterator(value);
}
Collection<Object> oldCollection = (Collection<Object>) entityAttributeAccessor.getValue(entity);
EntityManager entityManager = context.getEntityManager();
if (inverseRemoveStrategy == InverseCollectionElementAttributeFlusher.Strategy.REMOVE) {
for (Object o : oldCollection) {
if (!newCollection.contains(o)) {
entityManager.remove(o);
}
}
}
}
entityAttributeAccessor.setValue(entity, newCollection);
} else {
entityAttributeAccessor.setValue(entity, value);
}
// TODO: collectionRemoveListener?
}
}
}
use of com.blazebit.persistence.view.impl.entity.ViewToEntityMapper in project blaze-persistence by Blazebit.
the class MapAttributeFlusher 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 RecordingMap<?, ?, ?>) {
RecordingMap<?, ?, ?> recordingCollection = (RecordingMap<?, ?, ?>) current;
if (recordingCollection.hasActions()) {
return DirtyKind.MUTATED;
}
if (keyDescriptor.shouldFlushMutations() || elementDescriptor.shouldFlushMutations()) {
if (keyDescriptor.shouldFlushMutations() && !keyDescriptor.supportsDirtyCheck() || elementDescriptor.shouldFlushMutations() && !elementDescriptor.supportsDirtyCheck()) {
// If we don't support dirty checking we always have to assume dirtyness
return DirtyKind.MUTATED;
}
// The dirty checking fast-path can only work when the key and the element are either immutable or report changes via the DirtyTracker API
if (!recordingCollection.$$_isDirty() && (!keyDescriptor.shouldFlushMutations() || keyDescriptor.shouldFlushMutations() && keyDescriptor.isSubview()) && (!elementDescriptor.shouldFlushMutations() || elementDescriptor.shouldFlushMutations() && elementDescriptor.isSubview())) {
return DirtyKind.NONE;
}
ViewToEntityMapper keyMapper = keyDescriptor.getViewToEntityMapper();
ViewToEntityMapper valueMapper = elementDescriptor.getViewToEntityMapper();
BasicUserType<Object> keyUserType = keyDescriptor.getBasicUserType();
BasicUserType<Object> valueUserType = elementDescriptor.getBasicUserType();
for (Map.Entry<?, ?> entry : recordingCollection.entrySet()) {
Object key = entry.getKey();
Object value = entry.getValue();
if (keyDescriptor.supportsDirtyCheck()) {
if (keyDescriptor.isSubview()) {
if (key instanceof DirtyStateTrackable) {
DirtyStateTrackable element = (DirtyStateTrackable) key;
if (keyMapper.getUpdater(value).getDirtyChecker().getDirtyKind(element, element) == DirtyKind.MUTATED) {
return DirtyKind.MUTATED;
}
}
} else {
String[] dirtyProperties = keyUserType.getDirtyProperties(value);
if (dirtyProperties != null) {
return DirtyKind.MUTATED;
}
}
}
if (elementDescriptor.supportsDirtyCheck()) {
if (elementDescriptor.isSubview()) {
if (value instanceof DirtyStateTrackable) {
DirtyStateTrackable element = (DirtyStateTrackable) value;
if (valueMapper.getUpdater(value).getDirtyChecker().getDirtyKind(element, element) == DirtyKind.MUTATED) {
return DirtyKind.MUTATED;
}
}
} else {
String[] dirtyProperties = valueUserType.getDirtyProperties(value);
if (dirtyProperties != null) {
return DirtyKind.MUTATED;
}
}
}
}
} else {
// Since initial == current, nothing changed
return DirtyKind.NONE;
}
}
} else {
if (initial.size() != current.size()) {
return DirtyKind.MUTATED;
}
if (keyDescriptor.shouldFlushMutations() || elementDescriptor.shouldFlushMutations()) {
if (keyDescriptor.shouldFlushMutations() && !keyDescriptor.supportsDirtyCheck() || elementDescriptor.shouldFlushMutations() && !elementDescriptor.supportsDirtyCheck()) {
if ((!keyDescriptor.shouldFlushMutations() || keyDescriptor.isSubview() || keyDescriptor.shouldFlushMutations() && keyDescriptor.getBasicUserType().supportsDeepCloning()) && (!elementDescriptor.shouldFlushMutations() || elementDescriptor.isSubview() || elementDescriptor.shouldFlushMutations() && 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;
}
}
ViewToEntityMapper keyMapper = keyDescriptor.getViewToEntityMapper();
ViewToEntityMapper valueMapper = elementDescriptor.getViewToEntityMapper();
BasicUserType<Object> keyUserType = keyDescriptor.getBasicUserType();
BasicUserType<Object> valueUserType = elementDescriptor.getBasicUserType();
for (Map.Entry<?, ?> entry : current.entrySet()) {
Object key = entry.getKey();
Object value = entry.getValue();
if (!Objects.equals(initial.get(key), value)) {
return DirtyKind.MUTATED;
}
if (keyDescriptor.supportsDirtyCheck()) {
if (keyDescriptor.isSubview()) {
if (key instanceof DirtyStateTrackable) {
DirtyStateTrackable element = (DirtyStateTrackable) key;
if (keyMapper.getUpdater(value).getDirtyChecker().getDirtyKind(element, element) == DirtyKind.MUTATED) {
return DirtyKind.MUTATED;
}
}
} else {
String[] dirtyProperties = keyUserType.getDirtyProperties(value);
if (dirtyProperties != null) {
return DirtyKind.MUTATED;
}
}
}
if (elementDescriptor.supportsDirtyCheck()) {
if (elementDescriptor.isSubview()) {
if (value instanceof DirtyStateTrackable) {
DirtyStateTrackable element = (DirtyStateTrackable) value;
if (valueMapper.getUpdater(value).getDirtyChecker().getDirtyKind(element, element) == DirtyKind.MUTATED) {
return DirtyKind.MUTATED;
}
}
} else {
String[] dirtyProperties = valueUserType.getDirtyProperties(value);
if (dirtyProperties != null) {
return DirtyKind.MUTATED;
}
}
}
}
} else {
return collectionEquals(initial, current) ? DirtyKind.NONE : DirtyKind.MUTATED;
}
}
return DirtyKind.NONE;
}
use of com.blazebit.persistence.view.impl.entity.ViewToEntityMapper in project blaze-persistence by Blazebit.
the class MapAttributeFlusher method addElements.
protected void addElements(UpdateContext context, Object ownerView, Object view, Map<Object, Object> removedAllObjects, boolean flushAtOnce, V value, Map<Object, Object> embeddablesToUpdate, FusedMapActions fusedCollectionActions, boolean initialKnown) {
Map<Object, Object> appends;
String mapping = getMapping();
if (fusedCollectionActions == null || !removedAllObjects.isEmpty()) {
appends = (Map<Object, Object>) value;
Iterator<Map.Entry<Object, Object>> iterator = removedAllObjects.entrySet().iterator();
List<Object> removeWrappers = null;
while (iterator.hasNext()) {
Map.Entry<Object, Object> entry = iterator.next();
Object currentValue = value.get(entry.getKey());
if (currentValue != null) {
if (!currentValue.equals(entry.getValue())) {
if (removeWrappers == null) {
removeWrappers = new ArrayList<>();
}
removeWrappers.add(new FusedMapActions.RemoveWrapper(entry.getKey()));
}
iterator.remove();
}
}
if (removeWrappers != null) {
for (Object removeWrapper : removeWrappers) {
removedAllObjects.put(removeWrapper, null);
}
}
} else {
Map<Object, Object> replaces = fusedCollectionActions.getReplaces();
if (replaces.size() != 0 || embeddablesToUpdate != null && !embeddablesToUpdate.isEmpty()) {
UpdateCriteriaBuilder<?> updateCb = context.getEntityViewManager().getCriteriaBuilderFactory().updateCollection(context.getEntityManager(), ownerEntityClass, "e", mapping);
updateCb.setExpression(mapping, ":element");
updateCb.setWhereExpression(ownerIdWhereFragment);
updateCb.where("KEY(" + mapping + ")").eqExpression(":key");
Query query = updateCb.getQuery();
if (replaces.size() != 0) {
ownerIdFlusher.flushQuery(context, null, null, query, ownerView, view, ownerIdFlusher.getViewAttributeAccessor().getValue(ownerView), null, null);
boolean checkTransient = elementDescriptor.isJpaEntity() && !elementDescriptor.shouldJpaPersist();
ViewToEntityMapper keyViewToEntityMapper = keyDescriptor.getLoadOnlyViewToEntityMapper();
ViewToEntityMapper valueViewToEntityMapper = elementDescriptor.getLoadOnlyViewToEntityMapper();
for (Map.Entry<Object, Object> replace : replaces.entrySet()) {
Object k = replace.getKey();
Object v = replace.getValue();
if (keyViewToEntityMapper == null) {
if (checkTransient && keyDescriptor.getBasicUserType().shouldPersist(k)) {
throw new IllegalStateException("Collection " + attributeName + " references an unsaved transient instance - save the transient instance before flushing: " + k);
}
} else {
k = keyViewToEntityMapper.applyToEntity(context, null, k);
}
if (valueViewToEntityMapper == null) {
if (checkTransient && elementDescriptor.getBasicUserType().shouldPersist(v)) {
throw new IllegalStateException("Collection " + attributeName + " references an unsaved transient instance - save the transient instance before flushing: " + v);
}
} else {
v = valueViewToEntityMapper.applyToEntity(context, null, v);
}
query.setParameter("key", k);
query.setParameter("element", v);
query.executeUpdate();
}
}
if (embeddablesToUpdate != null && !embeddablesToUpdate.isEmpty()) {
for (Map.Entry<Object, Object> entry : embeddablesToUpdate.entrySet()) {
query.setParameter("key", entry.getKey());
query.setParameter("element", entry.getValue());
query.executeUpdate();
}
}
}
appends = fusedCollectionActions.getAdded();
}
if (appends.size() > 0) {
InsertCriteriaBuilder<?> insertCb = context.getEntityViewManager().getCriteriaBuilderFactory().insertCollection(context.getEntityManager(), ownerEntityClass, mapping);
String keyEntityIdAttributeName = keyDescriptor.getEntityIdAttributeName();
String keyAttributeIdAttributeName = keyDescriptor.getAttributeIdAttributeName();
if (keyEntityIdAttributeName == null) {
insertCb.fromValues(ownerEntityClass, "KEY(" + mapping + ")", "key", 1);
} else if (keyEntityIdAttributeName.equals(keyAttributeIdAttributeName)) {
insertCb.fromIdentifiableValues((Class<Object>) keyDescriptor.getJpaType(), "key", 1);
} else {
insertCb.fromIdentifiableValues((Class<Object>) keyDescriptor.getJpaType(), keyAttributeIdAttributeName, "key", 1);
}
String entityIdAttributeName = elementDescriptor.getEntityIdAttributeName();
String attributeIdAttributeName = elementDescriptor.getAttributeIdAttributeName();
if (entityIdAttributeName == null) {
insertCb.fromValues(ownerEntityClass, mapping, "val", 1);
} else if (entityIdAttributeName.equals(attributeIdAttributeName)) {
insertCb.fromIdentifiableValues((Class<Object>) elementDescriptor.getJpaType(), "val", 1);
} else {
insertCb.fromIdentifiableValues((Class<Object>) elementDescriptor.getJpaType(), attributeIdAttributeName, "val", 1);
}
insertCb.bind("KEY(" + mapping + ")").select("key");
for (int i = 0; i < ownerIdBindFragments.length; i += 2) {
insertCb.bind(ownerIdBindFragments[i]).select(ownerIdBindFragments[i + 1]);
}
insertCb.bind(mapping).select("val");
Query query = insertCb.getQuery();
ownerIdFlusher.flushQuery(context, null, null, query, ownerView, view, ownerIdFlusher.getViewAttributeAccessor().getValue(ownerView), null, null);
// TODO: Use batching when we implement #657
Object[] singletonKeyArray = new Object[1];
Object[] singletonValueArray = new Object[1];
List<Object> singletonKeyList = Arrays.asList(singletonKeyArray);
List<Object> singletonValueList = Arrays.asList(singletonValueArray);
ViewToEntityMapper keyViewToEntityMapper = keyDescriptor.getLoadOnlyViewToEntityMapper();
ViewToEntityMapper valueViewToEntityMapper = elementDescriptor.getLoadOnlyViewToEntityMapper();
boolean checkTransient = elementDescriptor.isJpaEntity() && !elementDescriptor.shouldJpaPersist();
for (Map.Entry<Object, Object> entry : appends.entrySet()) {
Object k = entry.getKey();
Object v = entry.getValue();
if (k != null && v != null) {
if (keyViewToEntityMapper == null) {
if (checkTransient && keyDescriptor.getBasicUserType().shouldPersist(k)) {
throw new IllegalStateException("Collection " + attributeName + " references an unsaved transient instance - save the transient instance before flushing: " + k);
}
singletonKeyArray[0] = k;
} else {
singletonKeyArray[0] = keyViewToEntityMapper.applyToEntity(context, null, k);
}
if (valueViewToEntityMapper == null) {
if (checkTransient && elementDescriptor.getBasicUserType().shouldPersist(v)) {
throw new IllegalStateException("Collection " + attributeName + " references an unsaved transient instance - save the transient instance before flushing: " + v);
}
singletonValueArray[0] = v;
} else {
singletonValueArray[0] = valueViewToEntityMapper.applyToEntity(context, null, v);
}
query.setParameter("key", singletonKeyList);
query.setParameter("val", singletonValueList);
query.executeUpdate();
}
}
}
}
use of com.blazebit.persistence.view.impl.entity.ViewToEntityMapper in project blaze-persistence by Blazebit.
the class AbstractPluralAttributeFlusher method determineElementFlushers.
protected final boolean determineElementFlushers(UpdateContext context, TypeDescriptor typeDescriptor, List<CollectionElementAttributeFlusher<E, V>> elementFlushers, Iterable<?> values, List<? extends A> actions, V current) {
if (typeDescriptor.shouldFlushMutations()) {
if (typeDescriptor.isSubview()) {
final ViewToEntityMapper mapper = typeDescriptor.getViewToEntityMapper();
if (typeDescriptor.isIdentifiable()) {
for (Object o : values) {
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) {
elementFlushers.add(new UpdateCollectionElementAttributeFlusher<E, V>(flusher, element, optimisticLockProtected, mapper));
}
}
}
} else {
if (typeDescriptor.supportsDirtyCheck() && !typeDescriptor.isIdentifiable() && isIndexed()) {
addFlatViewElementFlushActions(context, typeDescriptor, (List<A>) actions, current);
} else {
for (Object o : values) {
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) {
// This is signalled by returning null
return true;
}
}
}
}
}
} else if (typeDescriptor.isJpaEntity()) {
for (Object element : values) {
if (typeDescriptor.getBasicUserType().shouldPersist(element) && typeDescriptor.shouldJpaPersist()) {
elementFlushers.add(createPersistFlusher(typeDescriptor, element));
} else if (element != null && typeDescriptor.shouldJpaMerge()) {
elementFlushers.add(createMergeFlusher(typeDescriptor, element));
}
}
} else if (typeDescriptor.getBasicUserType().supportsDirtyChecking()) {
for (Object element : values) {
String[] dirtyProperties = typeDescriptor.getBasicUserType().getDirtyProperties(element);
if (dirtyProperties != null) {
// This is signalled by returning null
return true;
}
}
} else if (canFlushSeparateCollectionOperations()) {
// This is signalled by returning null
return true;
} else {
throw new IllegalArgumentException("Element flushers for non-identifiable type not determinable: " + typeDescriptor);
}
}
return false;
}
Aggregations