Search in sources :

Example 1 with ViewToEntityMapper

use of com.blazebit.persistence.view.impl.entity.ViewToEntityMapper in project blaze-persistence by Blazebit.

the class IndexedListAttributeFlusher method addElements.

@Override
protected void addElements(UpdateContext context, Object ownerView, Object view, Collection<Object> removedAllObjects, boolean flushAtOnce, boolean removedAllWithoutCollectionActions, V value, List<Object> embeddablesToUpdate, FusedCollectionActions fusedCollectionActions, boolean initialKnown) {
    Collection<Object> appends;
    int appendIndex;
    String mapping = getMapping();
    if (fusedCollectionActions == null || !removedAllObjects.isEmpty()) {
        appends = (Collection<Object>) value;
        removedAllObjects.removeAll(appends);
        appendIndex = 0;
    } else {
        FusedCollectionIndexActions indexActions = (FusedCollectionIndexActions) fusedCollectionActions;
        List<FusedCollectionIndexActions.IndexTranslateOperation> translations = indexActions.getTranslations();
        if (translations.size() != 0) {
            UpdateCriteriaBuilder<?> updateCb = context.getEntityViewManager().getCriteriaBuilderFactory().updateCollection(context.getEntityManager(), ownerEntityClass, "e", mapping);
            updateCb.setExpression("INDEX(" + mapping + ")", "INDEX(" + mapping + ") + :offset");
            updateCb.setWhereExpression(ownerIdWhereFragment);
            updateCb.where("INDEX(" + mapping + ")").geExpression(":minIdx");
            updateCb.where("INDEX(" + mapping + ")").ltExpression(":maxIdx");
            Query query = updateCb.getQuery();
            ownerIdFlusher.flushQuery(context, null, null, query, ownerView, view, ownerIdFlusher.getViewAttributeAccessor().getValue(ownerView), null, null);
            for (int i = 0; i < translations.size(); i++) {
                FusedCollectionIndexActions.IndexTranslateOperation translation = translations.get(i);
                query.setParameter("minIdx", translation.getStartIndex());
                query.setParameter("maxIdx", translation.getEndIndex());
                query.setParameter("offset", translation.getOffset());
                query.executeUpdate();
            }
        }
        List<FusedCollectionIndexActions.ReplaceOperation> replaces = indexActions.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("INDEX(" + mapping + ")").eqExpression(":idx");
            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();
                if (elementDescriptor.getViewToEntityMapper() == null) {
                    for (int i = 0; i < replaces.size(); i++) {
                        FusedCollectionIndexActions.ReplaceOperation replace = replaces.get(i);
                        if (checkTransient && elementDescriptor.getBasicUserType().shouldPersist(replace.getNewObject())) {
                            throw new IllegalStateException("Collection " + attributeName + " references an unsaved transient instance - save the transient instance before flushing: " + replace.getNewObject());
                        }
                        query.setParameter("idx", replace.getIndex());
                        query.setParameter("element", replace.getNewObject());
                        query.executeUpdate();
                    }
                } else {
                    ViewToEntityMapper loadOnlyViewToEntityMapper = elementDescriptor.getLoadOnlyViewToEntityMapper();
                    for (int i = 0; i < replaces.size(); i++) {
                        FusedCollectionIndexActions.ReplaceOperation replace = replaces.get(i);
                        query.setParameter("idx", replace.getIndex());
                        query.setParameter("element", loadOnlyViewToEntityMapper.applyToEntity(context, null, replace.getNewObject()));
                        query.executeUpdate();
                    }
                }
            }
            if (embeddablesToUpdate != null && !embeddablesToUpdate.isEmpty()) {
                for (int i = 0; i < embeddablesToUpdate.size(); i++) {
                    query.setParameter("idx", i);
                    query.setParameter("element", embeddablesToUpdate.get(i));
                    query.executeUpdate();
                }
            }
        }
        appends = indexActions.getAdded(context);
        appendIndex = indexActions.getAppendIndex();
        removedAllObjects.removeAll(indexActions.getAdded());
    }
    if (appends.size() > 1 || appends.size() == 1 && appends.iterator().next() != null) {
        InsertCriteriaBuilder<?> insertCb = context.getEntityViewManager().getCriteriaBuilderFactory().insertCollection(context.getEntityManager(), ownerEntityClass, mapping);
        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);
        }
        if (initialKnown) {
            insertCb.bind("INDEX(" + mapping + ")").select("FUNCTION('TREAT_INTEGER', :idx)");
        } else {
            SubqueryBuilder<? extends InsertCriteriaBuilder<?>> subquery = insertCb.bind("INDEX(" + mapping + ")").selectSubquery("subquery", "COALESCE(subquery + 1, 0)").from(ownerEntityClass, "sub").select("MAX(INDEX(sub." + mapping + "))");
            for (int i = 0; i < ownerIdBindFragments.length; i += 2) {
                subquery.where("sub." + ownerIdBindFragments[i]).eqExpression(ownerIdBindFragments[i + 1]);
            }
            subquery.end();
        }
        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[] singletonArray = new Object[1];
        List<Object> singletonList = Arrays.asList(singletonArray);
        if (elementDescriptor.getViewToEntityMapper() == null) {
            boolean checkTransient = elementDescriptor.isJpaEntity() && !elementDescriptor.shouldJpaPersist();
            for (Object object : appends) {
                if (object != null) {
                    if (checkTransient && elementDescriptor.getBasicUserType().shouldPersist(object)) {
                        throw new IllegalStateException("Collection " + attributeName + " references an unsaved transient instance - save the transient instance before flushing: " + object);
                    }
                    singletonArray[0] = object;
                    if (initialKnown) {
                        query.setParameter("idx", appendIndex++);
                    }
                    query.setParameter("val", singletonList);
                    query.executeUpdate();
                }
            }
        } else {
            ViewToEntityMapper loadOnlyViewToEntityMapper = elementDescriptor.getLoadOnlyViewToEntityMapper();
            for (Object object : appends) {
                if (object != null) {
                    singletonArray[0] = loadOnlyViewToEntityMapper.applyToEntity(context, null, object);
                    if (initialKnown) {
                        query.setParameter("idx", appendIndex++);
                    }
                    query.setParameter("val", singletonList);
                    query.executeUpdate();
                }
            }
        }
    }
}
Also used : Query(javax.persistence.Query) ViewToEntityMapper(com.blazebit.persistence.view.impl.entity.ViewToEntityMapper)

Example 2 with ViewToEntityMapper

use of com.blazebit.persistence.view.impl.entity.ViewToEntityMapper in project blaze-persistence by Blazebit.

the class IndexedListAttributeFlusher method addFlatViewElementFlushActions.

@Override
protected void addFlatViewElementFlushActions(UpdateContext context, TypeDescriptor typeDescriptor, List<CollectionAction<?>> actions, V current) {
    final ViewToEntityMapper mapper = typeDescriptor.getViewToEntityMapper();
    for (int i = 0; i < current.size(); i++) {
        Object o = current.get(i);
        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 view was added through actions somehow
                // We will register a special ListSetAction if the view was not added through actions to issue an UPDATE statement
                // By default, since the view is dirty, we start with the state UPDATED and go through state transitions
                // based on the containment of the view in the added/removed objects collections of the actions
                EntryState state = EntryState.UPDATED;
                Object replacedObject = element;
                for (CollectionAction<?> action : actions) {
                    Collection<Object> removedObjects = action.getRemovedObjects();
                    if (identityContains(removedObjects, element)) {
                        if (identityContains(action.getAddedObjects(), element)) {
                            // This is a ListSetAction where the old and new object are the same instances
                            replacedObject = element;
                            state = EntryState.UPDATED;
                        } else {
                            state = state.onRemove();
                        }
                    } else if (identityContains(action.getAddedObjects(), element)) {
                        if (removedObjects.isEmpty()) {
                            state = state.onAdd();
                        } else {
                            // This is a ListSetAction which has only a single element, so this is safe
                            replacedObject = removedObjects.iterator().next();
                            state = EntryState.UPDATED;
                        }
                    }
                }
                // and there is no action that would flush the object changes already
                if (state == EntryState.UPDATED && replacedObject == element) {
                    // Using last = false is intentional to actually get a proper update instead of a delete and insert
                    actions.add(new ListSetAction<>(i, false, element, element));
                }
            }
        }
    }
}
Also used : MutableStateTrackable(com.blazebit.persistence.view.spi.type.MutableStateTrackable) ViewToEntityMapper(com.blazebit.persistence.view.impl.entity.ViewToEntityMapper)

Example 3 with ViewToEntityMapper

use of com.blazebit.persistence.view.impl.entity.ViewToEntityMapper in project blaze-persistence by Blazebit.

the class InverseFlusher method forAttribute.

public static <E> InverseFlusher<E> forAttribute(EntityViewManagerImpl evm, Map<Object, EntityViewUpdaterImpl> localCache, ManagedViewType<?> viewType, AbstractMethodAttribute<?, ?> attribute, TypeDescriptor childTypeDescriptor, EntityViewUpdaterImpl owner, String ownerMapping) {
    if (attribute.getMappedBy() != null) {
        String attributeLocation = attribute.getLocation();
        Type<?> elementType = attribute instanceof PluralAttribute<?, ?, ?> ? ((PluralAttribute<?, ?, ?>) attribute).getElementType() : ((SingularAttribute<?, ?>) attribute).getType();
        Class<?> elementEntityClass = null;
        AttributeAccessor parentReferenceAttributeAccessor = null;
        Mapper<Object, Object> parentEntityOnChildViewMapper = null;
        Mapper<Object, Object> parentEntityOnChildEntityAddMapper = null;
        Mapper<Object, Object> parentEntityOnChildEntityRemoveMapper = null;
        TargetViewClassBasedInverseViewToEntityMapper childViewToEntityMapper = null;
        InverseEntityToEntityMapper childEntityToEntityMapper = null;
        ViewToEntityMapper parentReferenceViewToEntityMapper = new LoadOnlyViewToEntityMapper(new ReferenceEntityLoader(evm, viewType, EntityViewUpdaterImpl.createViewIdMapper(evm, localCache, viewType)), Accessors.forViewId(evm, (ViewType<?>) viewType, true), evm.getEntityIdAccessor());
        ViewToEntityMapper childReferenceViewToEntityMapper = null;
        TypeDescriptor parentReferenceTypeDescriptor = TypeDescriptor.forInverseAttribute(parentReferenceViewToEntityMapper);
        if (attribute.getWritableMappedByMappings() != null) {
            // This happens when the mapped by attribute is insertable=false and updatable=false
            if (childTypeDescriptor.isSubview()) {
                ViewType<?> childViewType = (ViewType<?>) elementType;
                elementEntityClass = childViewType.getEntityClass();
                Map<Class<?>, Mapper<Object, Object>> mappers = new HashMap<>();
                for (ManagedViewType<?> type : attribute.getViewTypes()) {
                    Mapper<Object, Object> mapper = Mappers.forViewConvertToViewAttributeMapping(evm, (ViewType<Object>) viewType, (ViewType<Object>) type, attribute.getWritableMappedByMappings(), (Mapper<Object, Object>) Mappers.forEntityAttributeMappingConvertToViewAttributeMapping(evm, viewType.getEntityClass(), type, attribute.getWritableMappedByMappings()));
                    if (mapper == null) {
                        mapper = NoopMapper.INSTANCE;
                    }
                    mappers.put(type.getJavaType(), mapper);
                }
                parentEntityOnChildViewMapper = (Mapper<Object, Object>) Mappers.targetViewClassBasedMapper(mappers);
                parentEntityOnChildEntityAddMapper = parentEntityOnChildEntityRemoveMapper = (Mapper<Object, Object>) Mappers.forEntityAttributeMapping(evm, viewType.getEntityClass(), childViewType.getEntityClass(), attribute.getWritableMappedByMappings());
                childReferenceViewToEntityMapper = new LoadOrPersistViewToEntityMapper(attributeLocation, evm, childViewType.getJavaType(), attribute.getReadOnlyAllowedSubtypes(), attribute.getPersistCascadeAllowedSubtypes(), attribute.getUpdateCascadeAllowedSubtypes(), new ReferenceEntityLoader(evm, childViewType, EntityViewUpdaterImpl.createViewIdMapper(evm, localCache, childViewType)), Accessors.forViewId(evm, childViewType, true), evm.getEntityIdAccessor(), true, owner, ownerMapping, localCache);
            } else if (childTypeDescriptor.isJpaEntity()) {
                Class<?> childType = elementType.getJavaType();
                elementEntityClass = childType;
                parentEntityOnChildViewMapper = (Mapper<Object, Object>) Mappers.forEntityAttributeMapping(evm, viewType.getEntityClass(), childType, attribute.getWritableMappedByMappings());
                parentEntityOnChildEntityAddMapper = parentEntityOnChildEntityRemoveMapper = (Mapper<Object, Object>) Mappers.forEntityAttributeMapping(evm, viewType.getEntityClass(), elementEntityClass, attribute.getWritableMappedByMappings());
            }
        } else {
            if (childTypeDescriptor.isSubview()) {
                ViewType<?> childViewType = (ViewType<?>) elementType;
                elementEntityClass = childViewType.getEntityClass();
                parentReferenceAttributeAccessor = Accessors.forEntityMapping(evm, childViewType.getEntityClass(), attribute.getMappedBy());
                childReferenceViewToEntityMapper = new LoadOrPersistViewToEntityMapper(attributeLocation, evm, childViewType.getJavaType(), attribute.getReadOnlyAllowedSubtypes(), attribute.getPersistCascadeAllowedSubtypes(), attribute.getUpdateCascadeAllowedSubtypes(), new ReferenceEntityLoader(evm, childViewType, EntityViewUpdaterImpl.createViewIdMapper(evm, localCache, childViewType)), Accessors.forViewId(evm, childViewType, true), evm.getEntityIdAccessor(), true, owner, ownerMapping, localCache);
                parentEntityOnChildEntityAddMapper = parentEntityOnChildEntityRemoveMapper = Mappers.forAccessor(parentReferenceAttributeAccessor);
                Map<Class<?>, Mapper<Object, Object>> mappers = new HashMap<>();
                for (ManagedViewType<?> type : attribute.getViewTypes()) {
                    Mapper<Object, Object> mapper = (Mapper<Object, Object>) Mappers.forViewConvertToViewAttributeMapping(evm, (ViewType<Object>) viewType, (ViewType<Object>) type, attribute.getMappedBy(), null);
                    if (mapper == null) {
                        mapper = NoopMapper.INSTANCE;
                    }
                    mappers.put(type.getJavaType(), mapper);
                }
                parentEntityOnChildViewMapper = (Mapper<Object, Object>) Mappers.targetViewClassBasedMapper(mappers);
            } else if (childTypeDescriptor.isJpaEntity()) {
                Class<?> childType = elementType.getJavaType();
                elementEntityClass = childType;
                parentReferenceAttributeAccessor = Accessors.forEntityMapping(evm, childType, attribute.getMappedBy());
                parentEntityOnChildEntityAddMapper = parentEntityOnChildEntityRemoveMapper = Mappers.forAccessor(parentReferenceAttributeAccessor);
                parentEntityOnChildViewMapper = Mappers.forAccessor(parentReferenceAttributeAccessor);
            }
        }
        DirtyAttributeFlusher<?, Object, ? extends Object> parentReferenceAttributeFlusher;
        ManagedType<?> managedType = evm.getMetamodel().getEntityMetamodel().getManagedType(elementEntityClass);
        Attribute<?, ?> inverseAttribute = JpaMetamodelUtils.getAttribute(managedType, attribute.getMappedBy());
        // Many-To-Many relation can't be handled by the inverse flushers
        if (inverseAttribute != null && inverseAttribute.isCollection()) {
            // A collection can only have a single attribute, so it's safe to assume a SimpleMapper
            parentEntityOnChildEntityAddMapper = new CollectionAddMapper<>(parentEntityOnChildEntityAddMapper == null ? parentReferenceAttributeAccessor : ((SimpleMapper<Object, Object>) parentEntityOnChildEntityAddMapper).getAttributeAccessor());
            parentEntityOnChildEntityRemoveMapper = new CollectionRemoveMapper<>(parentEntityOnChildEntityRemoveMapper == null ? parentReferenceAttributeAccessor : ((SimpleMapper<Object, Object>) parentEntityOnChildEntityRemoveMapper).getAttributeAccessor());
            parentReferenceAttributeFlusher = new ParentCollectionReferenceAttributeFlusher<>(attributeLocation, attribute.getMappedBy(), viewType.getFlushStrategy(), parentReferenceAttributeAccessor, null, null, null, TypeDescriptor.forInverseCollectionAttribute(viewType.getEntityClass(), new EntityBasicUserType(evm.getJpaProvider())));
        } else {
            parentEntityOnChildEntityRemoveMapper = new NullMapper<>(parentEntityOnChildEntityRemoveMapper);
            parentReferenceAttributeFlusher = new ParentReferenceAttributeFlusher<>(evm, viewType.getEntityClass(), attributeLocation, attribute.getMappedBy(), attribute.getWritableMappedByMappings(), parentReferenceTypeDescriptor, parentReferenceAttributeAccessor, parentEntityOnChildViewMapper);
        }
        UnmappedAttributeCascadeDeleter deleter = null;
        String parentIdAttributeName = null;
        String childIdAttributeName = null;
        Class<?> childIdViewClass = null;
        // Only construct when orphanRemoval or delete cascading is enabled, orphanRemoval implies delete cascading
        if (attribute.isDeleteCascaded()) {
            EntityMetamodel entityMetamodel = evm.getMetamodel().getEntityMetamodel();
            ExtendedManagedType<?> ownerManagedType = entityMetamodel.getManagedType(ExtendedManagedType.class, viewType.getEntityClass());
            ExtendedManagedType<?> elementManagedType = entityMetamodel.getManagedType(ExtendedManagedType.class, elementEntityClass);
            parentIdAttributeName = ownerManagedType.getIdAttribute().getName();
            childIdAttributeName = elementManagedType.getIdAttribute().getName();
            String mapping = attribute.getMappedBy();
            if (mapping != null) {
                if (mapping.isEmpty()) {
                    deleter = new UnmappedWritableBasicAttributeSetNullCascadeDeleter(evm, ownerManagedType.getType(), elementManagedType, attribute.getWritableMappedByMappings());
                } else {
                    ExtendedAttribute extendedAttribute = elementManagedType.getAttribute(mapping);
                    if (childTypeDescriptor.isSubview()) {
                        if (elementType instanceof ViewType<?>) {
                            MethodAttribute<?, ?> idAttribute = ((ViewType<?>) elementType).getIdAttribute();
                            if (idAttribute.isSubview()) {
                                // in this case, we need to fetch the id as view as the deleter expects it this way
                                childIdViewClass = idAttribute.getJavaType();
                            }
                        }
                        deleter = new ViewTypeCascadeDeleter(childTypeDescriptor.getViewToEntityMapper());
                    } else if (childTypeDescriptor.isJpaEntity()) {
                        deleter = new UnmappedBasicAttributeCascadeDeleter(evm, mapping, extendedAttribute, mapping + "." + parentIdAttributeName, false);
                    }
                }
            }
        }
        if (childTypeDescriptor.isSubview()) {
            InverseViewToEntityMapper<?> first = null;
            Map<Class<?>, InverseViewToEntityMapper<?>> mappers = new HashMap<>();
            for (ManagedViewType<?> type : attribute.getViewTypes()) {
                InverseViewToEntityMapper inverseViewToEntityMapper = new InverseViewToEntityMapper(evm, localCache, (ViewType<?>) type, parentEntityOnChildViewMapper, parentEntityOnChildEntityAddMapper, parentEntityOnChildEntityRemoveMapper, childTypeDescriptor.getViewToEntityMapper(), parentReferenceAttributeFlusher, EntityViewUpdaterImpl.createIdFlusher(evm, localCache, (ViewType<?>) type, EntityViewUpdaterImpl.createViewIdMapper(evm, localCache, type)));
                mappers.put(type.getJavaType(), inverseViewToEntityMapper);
                if (type == elementType) {
                    first = inverseViewToEntityMapper;
                }
            }
            childViewToEntityMapper = new TargetViewClassBasedInverseViewToEntityMapper(first, mappers);
        } else if (childTypeDescriptor.isJpaEntity()) {
            Class<?> childType = elementType.getJavaType();
            childEntityToEntityMapper = new InverseEntityToEntityMapper(evm, evm.getMetamodel().getEntityMetamodel().entity(childType), parentEntityOnChildEntityAddMapper, parentEntityOnChildEntityRemoveMapper, parentReferenceAttributeFlusher);
        }
        return new InverseFlusher(viewType.getEntityClass(), attribute.getMapping(), parentIdAttributeName, childIdAttributeName, childIdViewClass, deleter, parentReferenceViewToEntityMapper, parentReferenceAttributeFlusher, parentEntityOnChildViewMapper, childViewToEntityMapper, childReferenceViewToEntityMapper, parentEntityOnChildEntityAddMapper, childEntityToEntityMapper);
    }
    return null;
}
Also used : LoadOrPersistViewToEntityMapper(com.blazebit.persistence.view.impl.entity.LoadOrPersistViewToEntityMapper) LoadOnlyViewToEntityMapper(com.blazebit.persistence.view.impl.entity.LoadOnlyViewToEntityMapper) HashMap(java.util.HashMap) CollectionRemoveMapper(com.blazebit.persistence.view.impl.mapper.CollectionRemoveMapper) LoadOrPersistViewToEntityMapper(com.blazebit.persistence.view.impl.entity.LoadOrPersistViewToEntityMapper) LoadOnlyViewToEntityMapper(com.blazebit.persistence.view.impl.entity.LoadOnlyViewToEntityMapper) NoopMapper(com.blazebit.persistence.view.impl.mapper.NoopMapper) InverseEntityToEntityMapper(com.blazebit.persistence.view.impl.entity.InverseEntityToEntityMapper) NullMapper(com.blazebit.persistence.view.impl.mapper.NullMapper) CollectionAddMapper(com.blazebit.persistence.view.impl.mapper.CollectionAddMapper) TargetViewClassBasedInverseViewToEntityMapper(com.blazebit.persistence.view.impl.entity.TargetViewClassBasedInverseViewToEntityMapper) InverseElementToEntityMapper(com.blazebit.persistence.view.impl.entity.InverseElementToEntityMapper) Mapper(com.blazebit.persistence.view.impl.mapper.Mapper) SimpleMapper(com.blazebit.persistence.view.impl.mapper.SimpleMapper) ViewToEntityMapper(com.blazebit.persistence.view.impl.entity.ViewToEntityMapper) InverseViewToEntityMapper(com.blazebit.persistence.view.impl.entity.InverseViewToEntityMapper) LoadOrPersistViewToEntityMapper(com.blazebit.persistence.view.impl.entity.LoadOrPersistViewToEntityMapper) LoadOnlyViewToEntityMapper(com.blazebit.persistence.view.impl.entity.LoadOnlyViewToEntityMapper) TargetViewClassBasedInverseViewToEntityMapper(com.blazebit.persistence.view.impl.entity.TargetViewClassBasedInverseViewToEntityMapper) ViewToEntityMapper(com.blazebit.persistence.view.impl.entity.ViewToEntityMapper) InverseViewToEntityMapper(com.blazebit.persistence.view.impl.entity.InverseViewToEntityMapper) TargetViewClassBasedInverseViewToEntityMapper(com.blazebit.persistence.view.impl.entity.TargetViewClassBasedInverseViewToEntityMapper) TargetViewClassBasedInverseViewToEntityMapper(com.blazebit.persistence.view.impl.entity.TargetViewClassBasedInverseViewToEntityMapper) InverseViewToEntityMapper(com.blazebit.persistence.view.impl.entity.InverseViewToEntityMapper) ExtendedAttribute(com.blazebit.persistence.spi.ExtendedAttribute) ReferenceEntityLoader(com.blazebit.persistence.view.impl.entity.ReferenceEntityLoader) InverseEntityToEntityMapper(com.blazebit.persistence.view.impl.entity.InverseEntityToEntityMapper) EntityBasicUserType(com.blazebit.persistence.view.impl.type.EntityBasicUserType) AttributeAccessor(com.blazebit.persistence.view.impl.accessor.AttributeAccessor) EntityMetamodel(com.blazebit.persistence.parser.EntityMetamodel) ManagedViewType(com.blazebit.persistence.view.metamodel.ManagedViewType) ViewType(com.blazebit.persistence.view.metamodel.ViewType)

Example 4 with ViewToEntityMapper

use of com.blazebit.persistence.view.impl.entity.ViewToEntityMapper in project blaze-persistence by Blazebit.

the class EntityViewUpdaterImpl method createPluralAttributeSubFlusher.

private DirtyAttributeFlusher<?, ?, ?> createPluralAttributeSubFlusher(EntityViewManagerImpl evm, Map<Object, EntityViewUpdaterImpl> localCache, ManagedViewTypeImplementor<?> viewType, AbstractMethodAttribute<?, ?> attribute, String name, Type<?> type, EntityViewUpdaterImpl owner, String ownerMapping) {
    EntityMetamodel entityMetamodel = evm.getMetamodel().getEntityMetamodel();
    String attributeName = attribute.getName() + "_" + name;
    String attributeMapping = attribute.getMapping();
    String attributeLocation = attribute.getLocation();
    Set<Type<?>> readOnlyAllowedSubtypes = attribute.getReadOnlyAllowedSubtypes();
    Set<Type<?>> persistAllowedSubtypes = attribute.getPersistCascadeAllowedSubtypes();
    Set<Type<?>> updateAllowedSubtypes = attribute.getUpdateCascadeAllowedSubtypes();
    if (type instanceof ManagedViewType<?>) {
        ManagedViewTypeImplementor<?> subviewType = (ManagedViewTypeImplementor<?>) type;
        if (!(subviewType.getJpaManagedType() instanceof EntityType<?>)) {
            // A singular attribute where the subview refers to an embeddable type
            EmbeddableUpdaterBasedViewToEntityMapper viewToEntityMapper = new EmbeddableUpdaterBasedViewToEntityMapper(attributeLocation, evm, subviewType.getJavaType(), readOnlyAllowedSubtypes, persistAllowedSubtypes, updateAllowedSubtypes, EntityLoaders.referenceLoaderForAttribute(evm, localCache, subviewType, attribute), false, null, owner, ownerMapping == null ? attributeMapping : ownerMapping + "." + attributeMapping, localCache);
            String parameterName = attributeName + "_";
            String updateFragment = attributeMapping + ".";
            return new EmbeddableAttributeFlusher<>(attributeName, attributeMapping, updateFragment, parameterName, false, false, false, null, null, viewToEntityMapper);
        } else {
            ViewTypeImplementor<?> attributeViewType = (ViewTypeImplementor<?>) subviewType;
            InitialValueAttributeAccessor viewAttributeAccessor = Accessors.forMutableViewAttribute(evm, attribute);
            AttributeAccessor subviewIdAccessor;
            ManagedType<?> ownerManagedType = owner == null ? viewType.getJpaManagedType() : owner.managedViewType.getJpaManagedType();
            EntityType<?> ownerEntityType = ownerManagedType instanceof EntityType<?> ? (EntityType<?>) ownerManagedType : null;
            String attributeElementIdMapping;
            if (ownerEntityType != null && attribute.getMapping() != null) {
                ExtendedManagedType<?> extendedManagedType = evm.getMetamodel().getEntityMetamodel().getManagedType(ExtendedManagedType.class, attributeViewType.getEntityClass());
                attributeElementIdMapping = TypeDescriptor.getAttributeElementIdentifier(evm, ownerEntityType, attribute.getName(), ownerMapping, attribute.getMapping(), extendedManagedType.getType());
            } else {
                attributeElementIdMapping = ((MappingAttribute<?, ?>) attributeViewType.getIdAttribute()).getMapping();
            }
            subviewIdAccessor = Accessors.forSubviewAssociationId(evm, attributeViewType, attributeElementIdMapping, true);
            Attribute<?, ?> attributeIdAttribute = attributeViewType.getJpaManagedType().getAttribute(attributeElementIdMapping);
            javax.persistence.metamodel.Type<?> attributeIdAttributeType = entityMetamodel.type(JpaMetamodelUtils.resolveFieldClass(attributeViewType.getEntityClass(), attributeIdAttribute));
            List<String> idComponentMappings;
            boolean requiresComponentWiseSetInUpdate = true;
            if (requiresComponentWiseSetInUpdate && attributeIdAttributeType instanceof EmbeddableType<?>) {
                // If the identifier used for the association is an embeddable, we must collect the individual attribute components since updates don't work on embeddables directly
                Set<Attribute<?, ?>> idAttributeComponents = (Set<Attribute<?, ?>>) ((EmbeddableType<?>) attributeIdAttributeType).getAttributes();
                idComponentMappings = new ArrayList<>(idAttributeComponents.size());
                for (Attribute<?, ?> idAttributeComponent : idAttributeComponents) {
                    idComponentMappings.add(attributeMapping + "." + attributeElementIdMapping + "." + idAttributeComponent);
                }
            } else {
                idComponentMappings = Collections.singletonList(attributeMapping + "." + attributeElementIdMapping);
            }
            String[] idAttributeMappings = idComponentMappings.toArray(new String[idComponentMappings.size()]);
            ViewToEntityMapper viewToEntityMapper = createViewToEntityMapper(attributeLocation, evm, localCache, ownerEntityType, attributeName, attributeMapping, attributeViewType, false, false, readOnlyAllowedSubtypes, persistAllowedSubtypes, updateAllowedSubtypes, EntityLoaders.referenceLoaderForAttribute(evm, localCache, attributeViewType, attribute.getViewTypes(), attributeElementIdMapping), owner, ownerMapping);
            String parameterName = attributeName;
            return new SubviewAttributeFlusher<>(attributeName, attributeMapping, false, true, false, false, false, subviewType.getConverter(), false, idAttributeMappings, parameterName, false, owner != null, null, viewAttributeAccessor, subviewIdAccessor, viewToEntityMapper, null, null);
        }
    } else {
        TypeDescriptor elementDescriptor = TypeDescriptor.forType(evm, localCache, this, attribute, type, owner, ownerMapping);
        String parameterName = attributeName;
        String updateFragment = attributeMapping;
        // TODO: Why?
        boolean supportsQueryFlush = !elementDescriptor.isJpaEmbeddable();
        return new BasicAttributeFlusher<>(attributeName, attributeMapping, supportsQueryFlush, false, true, false, false, false, null, elementDescriptor, updateFragment, parameterName, null, null, null, null, null);
    }
}
Also used : ViewTypeImplementor(com.blazebit.persistence.view.impl.metamodel.ViewTypeImplementor) ManagedViewTypeImplementor(com.blazebit.persistence.view.impl.metamodel.ManagedViewTypeImplementor) Set(java.util.Set) HashSet(java.util.HashSet) MappingAttribute(com.blazebit.persistence.view.metamodel.MappingAttribute) SingularAttribute(javax.persistence.metamodel.SingularAttribute) Attribute(javax.persistence.metamodel.Attribute) AbstractMethodAttribute(com.blazebit.persistence.view.impl.metamodel.AbstractMethodAttribute) PluralAttribute(com.blazebit.persistence.view.metamodel.PluralAttribute) ExtendedAttribute(com.blazebit.persistence.spi.ExtendedAttribute) MapAttribute(com.blazebit.persistence.view.metamodel.MapAttribute) MethodAttribute(com.blazebit.persistence.view.metamodel.MethodAttribute) InitialValueAttributeAccessor(com.blazebit.persistence.view.impl.accessor.InitialValueAttributeAccessor) EmbeddableAttributeFlusher(com.blazebit.persistence.view.impl.update.flush.EmbeddableAttributeFlusher) LoadOrPersistViewToEntityMapper(com.blazebit.persistence.view.impl.entity.LoadOrPersistViewToEntityMapper) LoadOnlyViewToEntityMapper(com.blazebit.persistence.view.impl.entity.LoadOnlyViewToEntityMapper) SimpleMapViewToEntityMapper(com.blazebit.persistence.view.impl.update.flush.SimpleMapViewToEntityMapper) UpdaterBasedViewToEntityMapper(com.blazebit.persistence.view.impl.entity.UpdaterBasedViewToEntityMapper) EmbeddableUpdaterBasedViewToEntityMapper(com.blazebit.persistence.view.impl.entity.EmbeddableUpdaterBasedViewToEntityMapper) MapViewToEntityMapper(com.blazebit.persistence.view.impl.entity.MapViewToEntityMapper) ViewToEntityMapper(com.blazebit.persistence.view.impl.entity.ViewToEntityMapper) SubviewAttributeFlusher(com.blazebit.persistence.view.impl.update.flush.SubviewAttributeFlusher) ManagedViewType(com.blazebit.persistence.view.metamodel.ManagedViewType) ManagedViewTypeImplementor(com.blazebit.persistence.view.impl.metamodel.ManagedViewTypeImplementor) EntityType(javax.persistence.metamodel.EntityType) ManagedType(javax.persistence.metamodel.ManagedType) BasicType(com.blazebit.persistence.view.metamodel.BasicType) EntityType(javax.persistence.metamodel.EntityType) Type(com.blazebit.persistence.view.metamodel.Type) ExtendedManagedType(com.blazebit.persistence.spi.ExtendedManagedType) VersionBasicUserType(com.blazebit.persistence.view.spi.type.VersionBasicUserType) ManagedViewType(com.blazebit.persistence.view.metamodel.ManagedViewType) EmbeddableType(javax.persistence.metamodel.EmbeddableType) ViewType(com.blazebit.persistence.view.metamodel.ViewType) TypeDescriptor(com.blazebit.persistence.view.impl.update.flush.TypeDescriptor) BasicAttributeFlusher(com.blazebit.persistence.view.impl.update.flush.BasicAttributeFlusher) InitialValueAttributeAccessor(com.blazebit.persistence.view.impl.accessor.InitialValueAttributeAccessor) AttributeAccessor(com.blazebit.persistence.view.impl.accessor.AttributeAccessor) EntityMetamodel(com.blazebit.persistence.parser.EntityMetamodel) EmbeddableUpdaterBasedViewToEntityMapper(com.blazebit.persistence.view.impl.entity.EmbeddableUpdaterBasedViewToEntityMapper)

Example 5 with ViewToEntityMapper

use of com.blazebit.persistence.view.impl.entity.ViewToEntityMapper in project blaze-persistence by Blazebit.

the class MapAttributeFlusher method mergeAndRequeue.

private boolean mergeAndRequeue(UpdateContext context, RecordingMap recordingCollection, Map<Object, Object> newCollection) {
    EntityManager em = context.getEntityManager();
    Map<Object, Object> queuedElements = null;
    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(newCollection);
    try {
        while (iter.hasNext()) {
            Map.Entry<Object, Object> entry = iter.next();
            Object key = entry.getKey();
            Object value = entry.getValue();
            if (flushKey) {
                key = persistOrMergeKey(context, em, key);
            } else if (keyMapper != null) {
                keyMapper.applyToEntity(context, null, key);
            }
            if (flushValue) {
                value = persistOrMerge(em, value);
            } else if (valueMapper != null) {
                valueMapper.applyToEntity(context, null, value);
            }
            if (key != entry.getKey()) {
                if (queuedElements == null) {
                    queuedElements = new HashMap<>(newCollection.size());
                }
                iter.remove();
                queuedElements.put(key, value);
                if (recordingCollection != null) {
                    recordingCollection.replaceActionElement(entry.getKey(), entry.getValue(), key, value);
                }
            } else if (value != entry.getValue()) {
                entry.setValue(value);
            }
        }
    } finally {
        resetRecordingIterator(newCollection);
    }
    if (queuedElements != null) {
        newCollection.putAll(queuedElements);
    }
    return true;
}
Also used : EntityManager(javax.persistence.EntityManager) 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)

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