Search in sources :

Example 16 with ViewToEntityMapper

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;
}
Also used : ArrayList(java.util.ArrayList) ViewToEntityMapper(com.blazebit.persistence.view.impl.entity.ViewToEntityMapper)

Example 17 with ViewToEntityMapper

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?
        }
    }
}
Also used : EntityManager(javax.persistence.EntityManager) RecordingCollection(com.blazebit.persistence.view.impl.collection.RecordingCollection) Collection(java.util.Collection) ViewToEntityMapper(com.blazebit.persistence.view.impl.entity.ViewToEntityMapper)

Example 18 with ViewToEntityMapper

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;
}
Also used : DirtyStateTrackable(com.blazebit.persistence.view.spi.type.DirtyStateTrackable) MapViewToEntityMapper(com.blazebit.persistence.view.impl.entity.MapViewToEntityMapper) ViewToEntityMapper(com.blazebit.persistence.view.impl.entity.ViewToEntityMapper) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map) IdentityHashMap(java.util.IdentityHashMap) AbstractMap(java.util.AbstractMap) RecordingMap(com.blazebit.persistence.view.impl.collection.RecordingMap) RecordingMap(com.blazebit.persistence.view.impl.collection.RecordingMap)

Example 19 with ViewToEntityMapper

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();
            }
        }
    }
}
Also used : Query(javax.persistence.Query) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map) IdentityHashMap(java.util.IdentityHashMap) AbstractMap(java.util.AbstractMap) RecordingMap(com.blazebit.persistence.view.impl.collection.RecordingMap) MapViewToEntityMapper(com.blazebit.persistence.view.impl.entity.MapViewToEntityMapper) ViewToEntityMapper(com.blazebit.persistence.view.impl.entity.ViewToEntityMapper)

Example 20 with ViewToEntityMapper

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;
}
Also used : MutableStateTrackable(com.blazebit.persistence.view.spi.type.MutableStateTrackable) ViewToEntityMapper(com.blazebit.persistence.view.impl.entity.ViewToEntityMapper)

Aggregations

ViewToEntityMapper (com.blazebit.persistence.view.impl.entity.ViewToEntityMapper)22 MapViewToEntityMapper (com.blazebit.persistence.view.impl.entity.MapViewToEntityMapper)11 HashMap (java.util.HashMap)10 LinkedHashMap (java.util.LinkedHashMap)10 Map (java.util.Map)10 AbstractMap (java.util.AbstractMap)8 RecordingMap (com.blazebit.persistence.view.impl.collection.RecordingMap)7 IdentityHashMap (java.util.IdentityHashMap)7 EntityMetamodel (com.blazebit.persistence.parser.EntityMetamodel)4 AttributeAccessor (com.blazebit.persistence.view.impl.accessor.AttributeAccessor)4 LoadOrPersistViewToEntityMapper (com.blazebit.persistence.view.impl.entity.LoadOrPersistViewToEntityMapper)4 ManagedViewType (com.blazebit.persistence.view.metamodel.ManagedViewType)4 MutableStateTrackable (com.blazebit.persistence.view.spi.type.MutableStateTrackable)4 ArrayList (java.util.ArrayList)4 ExtendedAttribute (com.blazebit.persistence.spi.ExtendedAttribute)3 ExtendedManagedType (com.blazebit.persistence.spi.ExtendedManagedType)3 InitialValueAttributeAccessor (com.blazebit.persistence.view.impl.accessor.InitialValueAttributeAccessor)3 EmbeddableUpdaterBasedViewToEntityMapper (com.blazebit.persistence.view.impl.entity.EmbeddableUpdaterBasedViewToEntityMapper)3 LoadOnlyViewToEntityMapper (com.blazebit.persistence.view.impl.entity.LoadOnlyViewToEntityMapper)3 UpdaterBasedViewToEntityMapper (com.blazebit.persistence.view.impl.entity.UpdaterBasedViewToEntityMapper)3