예제 #1
0
        /// <summary> Cascade an action to the child or children</summary>
        private Task CascadePropertyAsync(object parent, object child, IType type, CascadeStyle style, string propertyName, object anything, bool isCascadeDeleteEnabled, CancellationToken cancellationToken)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return(Task.FromCanceled <object>(cancellationToken));
            }
            try
            {
                if (child != null)
                {
                    if (type.IsAssociationType)
                    {
                        IAssociationType associationType = (IAssociationType)type;
                        if (CascadeAssociationNow(associationType))
                        {
                            return(CascadeAssociationAsync(parent, child, type, style, anything, isCascadeDeleteEnabled, cancellationToken));
                        }
                    }
                    else if (type.IsComponentType)
                    {
                        return(CascadeComponentAsync(parent, child, (IAbstractComponentType)type, propertyName, anything, cancellationToken));
                    }
                }
                else
                {
                    // potentially we need to handle orphan deletes for one-to-ones here...
                    if (type.IsEntityType && ((EntityType)type).IsLogicalOneToOne())
                    {
                        // We have a physical or logical one-to-one and from previous checks we know we
                        // have a null value.  See if the attribute cascade settings and action-type require
                        // orphan checking
                        if (style.HasOrphanDelete && action.DeleteOrphans)
                        {
                            // value is orphaned if loaded state for this property shows not null
                            // because it is currently null.
                            EntityEntry entry = eventSource.PersistenceContext.GetEntry(parent);
                            if (entry != null && entry.Status != Status.Saving)
                            {
                                EntityType entityType = (EntityType)type;
                                object     loadedValue;
                                if (!componentPathStack.Any())
                                {
                                    // association defined on entity
                                    loadedValue = entry.GetLoadedValue(propertyName);
                                }
                                else
                                {
                                    // association defined on component
                                    // todo : this is currently unsupported because of the fact that
                                    // we do not know the loaded state of this value properly
                                    // and doing so would be very difficult given how components and
                                    // entities are loaded (and how 'loaded state' is put into the
                                    // EntityEntry).  Solutions here are to either:
                                    //	1) properly account for components as a 2-phase load construct
                                    //  2) just assume the association was just now orphaned and
                                    //     issue the orphan delete.  This would require a special
                                    //     set of SQL statements though since we do not know the
                                    //     orphaned value, something a delete with a subquery to
                                    //     match the owner.
                                    loadedValue = null;
                                }

                                if (loadedValue != null)
                                {
                                    return(eventSource.DeleteAsync(entry.Persister.EntityName, loadedValue, false, null, cancellationToken));
                                }
                            }
                        }
                    }
                }
                return(Task.CompletedTask);
            }
            catch (System.Exception ex)
            {
                return(Task.FromException <object>(ex));
            }
        }
예제 #2
0
        /// <summary> Cascade an action to the child or children</summary>
        private void CascadeProperty(object parent, object child, IType type, CascadeStyle style, string propertyName, object anything, bool isCascadeDeleteEnabled)
        {
            if (child != null)
            {
                if (type.IsAssociationType)
                {
                    IAssociationType associationType = (IAssociationType)type;
                    if (CascadeAssociationNow(associationType))
                    {
                        CascadeAssociation(parent, child, type, style, anything, isCascadeDeleteEnabled);
                    }
                }
                else if (type.IsComponentType)
                {
                    CascadeComponent(parent, child, (IAbstractComponentType)type, propertyName, anything);
                }
            }
            else
            {
                // potentially we need to handle orphan deletes for one-to-ones here...
                if (type.IsEntityType && ((EntityType)type).IsLogicalOneToOne())
                {
                    // We have a physical or logical one-to-one and from previous checks we know we
                    // have a null value.  See if the attribute cascade settings and action-type require
                    // orphan checking
                    if (style.HasOrphanDelete && action.DeleteOrphans)
                    {
                        // value is orphaned if loaded state for this property shows not null
                        // because it is currently null.
                        EntityEntry entry = eventSource.PersistenceContext.GetEntry(parent);
                        if (entry != null && entry.Status != Status.Saving)
                        {
                            object loadedValue;
                            if (componentPathStack.Count == 0)
                            {
                                // association defined on entity
                                loadedValue = entry.GetLoadedValue(propertyName);

                                // Check this is not a null carrying proxy. The no-proxy load is currently handled by
                                // putting a proxy (!) flagged for unwrapping (even for non-constrained one-to-one,
                                // which association may be null) in the loadedState of the parent. The unwrap flag
                                // causes it to support having a null implementation, instead of throwing an entity
                                // not found error.
                                loadedValue = eventSource.PersistenceContext.UnproxyAndReassociate(loadedValue);
                            }
                            else
                            {
                                // association defined on component
                                // todo : this is currently unsupported because of the fact that
                                // we do not know the loaded state of this value properly
                                // and doing so would be very difficult given how components and
                                // entities are loaded (and how 'loaded state' is put into the
                                // EntityEntry).  Solutions here are to either:
                                //	1) properly account for components as a 2-phase load construct
                                //  2) just assume the association was just now orphaned and
                                //     issue the orphan delete.  This would require a special
                                //     set of SQL statements though since we do not know the
                                //     orphaned value, something a delete with a subquery to
                                //     match the owner.
                                loadedValue = null;
                            }

                            if (loadedValue != null)
                            {
                                eventSource.Delete(entry.Persister.EntityName, loadedValue, false, null);
                            }
                        }
                    }
                }
            }
        }