protected override JoinType GetJoinType(IAssociationType type, FetchMode config, string path, string lhsTable, string[] lhsColumns, bool nullable, int currentDepth, CascadeStyle cascadeStyle) { if (translator.IsJoin(path)) { return translator.GetJoinType(path); } else { if (translator.HasProjection) { return JoinType.None; } else { FetchMode fetchMode = translator.RootCriteria.GetFetchMode(path); if (IsDefaultFetchMode(fetchMode)) { return base.GetJoinType(type, config, path, lhsTable, lhsColumns, nullable, currentDepth, cascadeStyle); } else { if (fetchMode == FetchMode.Join) { IsDuplicateAssociation(lhsTable, lhsColumns, type); //deliberately ignore return value! return GetJoinType(nullable, currentDepth); } else { return JoinType.None; } } } } }
/// <summary> /// Constructs StandardProperty instances. /// </summary> /// <param name="name">The name by which the property can be referenced within /// its owner.</param> /// <param name="node">The node name to use for XML-based representation of this /// property.</param> /// <param name="type">The Hibernate Type of this property.</param> /// <param name="lazy">Should this property be handled lazily?</param> /// <param name="insertable">Is this property an insertable value?</param> /// <param name="updateable">Is this property an updateable value?</param> /// <param name="insertGenerated">Is this property generated in the database on insert?</param> /// <param name="updateGenerated">Is this property generated in the database on update?</param> /// <param name="nullable">Is this property a nullable value?</param> /// <param name="checkable">Is this property a checkable value?</param> /// <param name="versionable">Is this property a versionable value?</param> /// <param name="cascadeStyle">The cascade style for this property's value.</param> /// <param name="fetchMode">Any fetch mode defined for this property </param> public StandardProperty( String name, String node, IType type, bool lazy, bool insertable, bool updateable, bool insertGenerated, bool updateGenerated, bool nullable, bool checkable, bool versionable, CascadeStyle cascadeStyle, FetchMode? fetchMode) : base(name, node, type) { this.lazy = lazy; this.insertable = insertable; this.updateable = updateable; this.insertGenerated = insertGenerated; this.updateGenerated = updateGenerated; this.nullable = nullable; this.dirtyCheckable = checkable; this.versionable = versionable; this.cascadeStyle = cascadeStyle; this.fetchMode = fetchMode; }
/// <summary> /// Disable outer join fetching if this loader obtains an /// upgrade lock mode /// </summary> protected override bool IsJoinedFetchEnabled(IAssociationType type, FetchMode config, CascadeStyle cascadeStyle) { return lockMode.GreaterThan(LockMode.Read) ? false : base.IsJoinedFetchEnabled(type, config, cascadeStyle); }
/// <summary> /// Cascade an action from the parent entity instance to all its children. This /// form is typically called from within cascade actions. /// </summary> /// <param name="persister">The parent's entity persister </param> /// <param name="parent">The parent reference. </param> /// <param name="anything"> /// Typically some form of cascade-local cache /// which is specific to each CascadingAction type /// </param> /// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param> public async Task CascadeOnAsync(IEntityPersister persister, object parent, object anything, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (persister.HasCascades || action.RequiresNoCascadeChecking) { log.Info("processing cascade " + action + " for: " + persister.EntityName); IType[] types = persister.PropertyTypes; CascadeStyle[] cascadeStyles = persister.PropertyCascadeStyles; bool hasUninitializedLazyProperties = persister.HasUninitializedLazyProperties(parent); for (int i = 0; i < types.Length; i++) { CascadeStyle style = cascadeStyles[i]; string propertyName = persister.PropertyNames[i]; if (hasUninitializedLazyProperties && persister.PropertyLaziness[i] && !action.PerformOnLazyProperty) { //do nothing to avoid a lazy property initialization continue; } if (style.DoCascade(action)) { await(CascadePropertyAsync(parent, persister.GetPropertyValue(parent, i), types[i], style, propertyName, anything, false, cancellationToken)).ConfigureAwait(false); } else if (action.RequiresNoCascadeChecking) { await(action.NoCascadeAsync(eventSource, persister.GetPropertyValue(parent, i), parent, persister, i, cancellationToken)).ConfigureAwait(false); } } log.Info("done processing cascade " + action + " for: " + persister.EntityName); } }
/// <summary> /// Cascade to the collection elements /// </summary> /// <param name="action"></param> /// <param name="style"></param> /// <param name="collectionType"></param> /// <param name="elemType"></param> /// <param name="child"></param> /// <param name="cascadeVia"></param> /// <param name="session"></param> /// <param name="anything"></param> private static void CascadeCollection( CascadingAction action, CascadeStyle style, PersistentCollectionType collectionType, IType elemType, object child, CascadePoint cascadeVia, ISessionImplementor session, object anything) { // cascade to current collection elements if (log.IsDebugEnabled) { log.Debug("cascading to collection: " + collectionType.Role); } ICollection iter = action.CascadableChildrenCollection(collectionType, child); foreach (object obj in iter) { Cascade(session, obj, elemType, action, style, cascadeVia, anything); } // handle oprhaned entities!! if (style.HasOrphanDelete && action.DeleteOrphans() && child is PersistentCollection) { // We can do the cast since orphan-delete does not apply to: // 1. newly instatiated collections // 2. arrays ( we can't track orphans for detached arrays) DeleteOrphans(child as PersistentCollection, session); } }
/// <summary> /// Cascade an action from the parent entity instance to all its children. This /// form is typically called from within cascade actions. /// </summary> /// <param name="persister">The parent's entity persister </param> /// <param name="parent">The parent reference. </param> /// <param name="anything"> /// Typically some form of cascade-local cache /// which is specific to each CascadingAction type /// </param> public void CascadeOn(IEntityPersister persister, object parent, object anything) { if (persister.HasCascades || action.RequiresNoCascadeChecking) { log.Info("processing cascade {0} for: {1}", action, persister.EntityName); IType[] types = persister.PropertyTypes; CascadeStyle[] cascadeStyles = persister.PropertyCascadeStyles; bool hasUninitializedLazyProperties = persister.HasUninitializedLazyProperties(parent); for (int i = 0; i < types.Length; i++) { CascadeStyle style = cascadeStyles[i]; string propertyName = persister.PropertyNames[i]; if (hasUninitializedLazyProperties && persister.PropertyLaziness[i] && !action.PerformOnLazyProperty) { //do nothing to avoid a lazy property initialization continue; } if (style.DoCascade(action)) { CascadeProperty(parent, persister.GetPropertyValue(parent, i), types[i], style, propertyName, anything, false); } else if (action.RequiresNoCascadeChecking) { action.NoCascade(eventSource, persister.GetPropertyValue(parent, i), parent, persister, i); } } log.Info("done processing cascade {0} for: {1}", action, persister.EntityName); } }
/// <summary> /// Cascade an action to the child or children /// </summary> /// <param name="session"></param> /// <param name="child"></param> /// <param name="type"></param> /// <param name="action"></param> /// <param name="style"></param> /// <param name="cascadeTo"></param> /// <param name="anything"></param> private static void Cascade( ISessionImplementor session, object child, IType type, CascadingAction action, CascadeStyle style, CascadePoint cascadeTo, object anything) { if (child != null) { if (type.IsAssociationType) { if ((( IAssociationType )type).ForeignKeyType.CascadeNow(cascadeTo)) { if (type.IsEntityType || type.IsObjectType) { action.Cascade(session, child, anything); } else if (type.IsPersistentCollectionType) { CascadePoint cascadeVia; if (cascadeTo == CascadePoint.CascadeAfterInsertBeforeDelete) { cascadeVia = CascadePoint.CascadeAfterInsertBeforeDeleteViaCollection; } else { cascadeVia = cascadeTo; } PersistentCollectionType pctype = ( PersistentCollectionType )type; ICollectionPersister persister = session.Factory.GetCollectionPersister(pctype.Role); IType elemType = persister.ElementType; // cascade to current collection elements if (elemType.IsEntityType || elemType.IsObjectType || elemType.IsComponentType) { CascadeCollection(action, style, pctype, elemType, child, cascadeVia, session, anything); } } } } else if (type.IsComponentType) { IAbstractComponentType ctype = (( IAbstractComponentType )type); object[] children = ctype.GetPropertyValues(child, session); IType[] types = ctype.Subtypes; for (int i = 0; i < types.Length; i++) { CascadeStyle componentPropertyStyle = ctype.Cascade(i); if (componentPropertyStyle.DoCascade(action)) { Cascade(session, children[i], types[i], action, componentPropertyStyle, cascadeTo, anything); } } } } }
/// <summary> Cascade an action to a to-one association or any type</summary> private void CascadeToOne(object child, IType type, CascadeStyle style, object anything, bool isCascadeDeleteEnabled) { string entityName = type.IsEntityType ? ((EntityType)type).GetAssociatedEntityName() : null; if (style.ReallyDoCascade(action)) { //not really necessary, but good for consistency... action.Cascade(eventSource, child, entityName, anything, isCascadeDeleteEnabled); } }
private void CascadeAssociation(object parent, object child, IType type, CascadeStyle style, object anything, bool isCascadeDeleteEnabled) { if (type.IsEntityType || type.IsAnyType) { CascadeToOne(parent, child, type, style, anything, isCascadeDeleteEnabled); } else if (type.IsCollectionType) { CascadeCollection(parent, child, style, anything, (CollectionType)type); } }
private void CascadeComponent(object parent, object child, IAbstractComponentType componentType, object anything) { object[] children = componentType.GetPropertyValues(child, eventSource); IType[] types = componentType.Subtypes; for (int i = 0; i < types.Length; i++) { CascadeStyle componentPropertyStyle = componentType.GetCascadeStyle(i); if (componentPropertyStyle.DoCascade(action)) { CascadeProperty(parent, children[i], types[i], componentPropertyStyle, anything, false); } } }
private async Task CascadeComponentAsync(object parent, object child, IAbstractComponentType componentType, string componentPropertyName, object anything, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); componentPathStack.Push(componentPropertyName); object[] children = await(componentType.GetPropertyValuesAsync(child, eventSource, cancellationToken)).ConfigureAwait(false); IType[] types = componentType.Subtypes; for (int i = 0; i < types.Length; i++) { CascadeStyle componentPropertyStyle = componentType.GetCascadeStyle(i); string subPropertyName = componentType.PropertyNames[i]; if (componentPropertyStyle.DoCascade(action)) { await(CascadePropertyAsync(parent, children[i], types[i], componentPropertyStyle, subPropertyName, anything, false, cancellationToken)).ConfigureAwait(false); } } componentPathStack.Pop(); }
/// <summary> Cascade an action to a to-one association or any type</summary> private void CascadeToOne(object parent, object child, IType type, CascadeStyle style, object anything, bool isCascadeDeleteEnabled) { string entityName = type.IsEntityType ? ((EntityType)type).GetAssociatedEntityName() : null; if (style.ReallyDoCascade(action)) { //not really necessary, but good for consistency... eventSource.PersistenceContext.AddChildParent(child, parent); try { action.Cascade(eventSource, child, entityName, anything, isCascadeDeleteEnabled); } finally { eventSource.PersistenceContext.RemoveChildParent(child); } } }
/// <summary> Cascade an action to the child or children</summary> private void CascadeProperty(object parent, object child, IType type, CascadeStyle style, 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, anything); } } }
/// <summary> /// Constructs VersionProperty instances. /// </summary> /// <param name="name">The name by which the property can be referenced within /// its owner.</param> /// <param name="node">The node name to use for XML-based representation of this /// property.</param> /// <param name="type">The Hibernate Type of this property.</param> /// <param name="lazy">Should this property be handled lazily?</param> /// <param name="insertable">Is this property an insertable value?</param> /// <param name="updateable">Is this property an updateable value?</param> /// <param name="insertGenerated">Is this property generated in the database on insert?</param> /// <param name="updateGenerated">Is this property generated in the database on update?</param> /// <param name="nullable">Is this property a nullable value?</param> /// <param name="checkable">Is this property a checkable value?</param> /// <param name="versionable">Is this property a versionable value?</param> /// <param name="cascadeStyle">The cascade style for this property's value.</param> /// <param name="unsavedValue">The value which, if found as the value of /// this (i.e., the version) property, represents new (i.e., un-saved) /// instances of the owning entity.</param> public VersionProperty( string name, string node, IType type, bool lazy, bool insertable, bool updateable, bool insertGenerated, bool updateGenerated, bool nullable, bool checkable, bool versionable, CascadeStyle cascadeStyle, VersionValue unsavedValue) : base( name, node, type, lazy, insertable, updateable, insertGenerated, updateGenerated, nullable, checkable, versionable, cascadeStyle, null) { this.unsavedValue = unsavedValue; }
/// <summary> Cascade an action to a collection</summary> private void CascadeCollection(object parent, object child, CascadeStyle style, object anything, CollectionType type) { ICollectionPersister persister = eventSource.Factory.GetCollectionPersister(type.Role); IType elemType = persister.ElementType; CascadePoint oldCascadeTo = point; if (point == CascadePoint.AfterInsertBeforeDelete) { point = CascadePoint.AfterInsertBeforeDeleteViaCollection; } //cascade to current collection elements if (elemType.IsEntityType || elemType.IsAnyType || elemType.IsComponentType) { CascadeCollectionElements(parent, child, type, style, elemType, anything, persister.CascadeDeleteEnabled); } point = oldCascadeTo; }
/// <summary> Cascade an action to a collection</summary> private async Task CascadeCollectionAsync(object parent, object child, CascadeStyle style, object anything, CollectionType type, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ICollectionPersister persister = eventSource.Factory.GetCollectionPersister(type.Role); IType elemType = persister.ElementType; CascadePoint oldCascadeTo = point; if (point == CascadePoint.AfterInsertBeforeDelete) { point = CascadePoint.AfterInsertBeforeDeleteViaCollection; } //cascade to current collection elements if (elemType.IsEntityType || elemType.IsAnyType || elemType.IsComponentType) { await(CascadeCollectionElementsAsync(parent, child, type, style, elemType, anything, persister.CascadeDeleteEnabled, cancellationToken)).ConfigureAwait(false); } point = oldCascadeTo; }
/// <summary> /// Cascade an action from the parent object to all its children. /// </summary> /// <param name="session"></param> /// <param name="persister"></param> /// <param name="parent"></param> /// <param name="action"></param> /// <param name="cascadeTo"></param> /// <param name="anything"></param> public static void Cascade(ISessionImplementor session, IClassPersister persister, object parent, CascadingAction action, CascadePoint cascadeTo, object anything) { if (persister.HasCascades) { if (log.IsDebugEnabled) { log.Debug("processing cascades for: " + persister.ClassName); } IType[] types = persister.PropertyTypes; CascadeStyle[] cascadeStyles = persister.PropertyCascadeStyles; for (int i = 0; i < types.Length; i++) { CascadeStyle style = cascadeStyles[i]; if (style.DoCascade(action)) { Cascade(session, persister.GetPropertyValue(parent, i), types[i], action, style, cascadeTo, anything); } } if (log.IsDebugEnabled) { log.Debug("done processing cascades for: " + persister.ClassName); } } }
/// <summary> /// The superclass deliberately excludes collections /// </summary> protected override bool IsJoinedFetchEnabled(IAssociationType type, FetchMode config, CascadeStyle cascadeStyle) { return IsJoinedFetchEnabledInMapping(config, type); }
/// <summary> Cascade to the collection elements</summary> private void CascadeCollectionElements(object parent, object child, CollectionType collectionType, CascadeStyle style, IType elemType, object anything, bool isCascadeDeleteEnabled) { bool reallyDoCascade = style.ReallyDoCascade(action) && child != CollectionType.UnfetchedCollection; if (reallyDoCascade) { log.Info("cascade {0} for collection: {1}", action, collectionType.Role); foreach (object o in action.GetCascadableChildrenIterator(eventSource, collectionType, child)) { CascadeProperty(parent, o, elemType, style, null, anything, isCascadeDeleteEnabled); } log.Info("done cascade {0} for collection: {1}", action, collectionType.Role); } var childAsPersColl = child as IPersistentCollection; bool deleteOrphans = style.HasOrphanDelete && action.DeleteOrphans && elemType.IsEntityType && childAsPersColl != null; //a newly instantiated collection can't have orphans if (deleteOrphans) { // handle orphaned entities!! log.Info("deleting orphans for collection: {0}", collectionType.Role); // we can do the cast since orphan-delete does not apply to: // 1. newly instantiated collections // 2. arrays (we can't track orphans for detached arrays) string entityName = collectionType.GetAssociatedEntityName(eventSource.Factory); DeleteOrphans(entityName, childAsPersColl); log.Info("done deleting orphans for collection: {0}", collectionType.Role); } }
/// <summary> Cascade an action to a collection</summary> private void CascadeCollection(object child, CascadeStyle style, object anything, CollectionType type) { ICollectionPersister persister = eventSource.Factory.GetCollectionPersister(type.Role); IType elemType = persister.ElementType; CascadePoint oldCascadeTo = point; if (point == CascadePoint.AfterInsertBeforeDelete) point = CascadePoint.AfterInsertBeforeDeleteViaCollection; //cascade to current collection elements if (elemType.IsEntityType || elemType.IsAnyType || elemType.IsComponentType) CascadeCollectionElements(child, type, style, elemType, anything, persister.CascadeDeleteEnabled); point = oldCascadeTo; }
/// <summary> Cascade to the collection elements</summary> private void CascadeCollectionElements(object child, CollectionType collectionType, CascadeStyle style, IType elemType, object anything, bool isCascadeDeleteEnabled) { // we can't cascade to non-embedded elements bool embeddedElements = eventSource.EntityMode != EntityMode.Xml || ((EntityType) collectionType.GetElementType(eventSource.Factory)).IsEmbeddedInXML; bool reallyDoCascade = style.ReallyDoCascade(action) && embeddedElements && child != CollectionType.UnfetchedCollection; if (reallyDoCascade) { log.Info("cascade " + action + " for collection: " + collectionType.Role); foreach (object o in action.GetCascadableChildrenIterator(eventSource, collectionType, child)) CascadeProperty(o, elemType, style, anything, isCascadeDeleteEnabled); log.Info("done cascade " + action + " for collection: " + collectionType.Role); } var childAsPersColl = child as IPersistentCollection; bool deleteOrphans = style.HasOrphanDelete && action.DeleteOrphans && elemType.IsEntityType && childAsPersColl != null; //a newly instantiated collection can't have orphans if (deleteOrphans) { // handle orphaned entities!! log.Info("deleting orphans for collection: " + collectionType.Role); // we can do the cast since orphan-delete does not apply to: // 1. newly instantiated collections // 2. arrays (we can't track orphans for detached arrays) string entityName = collectionType.GetAssociatedEntityName(eventSource.Factory); DeleteOrphans(entityName, childAsPersColl); log.Info("done deleting orphans for collection: " + collectionType.Role); } }
/// <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)); } }
/// <summary> Cascade to the collection elements</summary> private async Task CascadeCollectionElementsAsync(object parent, object child, CollectionType collectionType, CascadeStyle style, IType elemType, object anything, bool isCascadeDeleteEnabled, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); bool reallyDoCascade = style.ReallyDoCascade(action) && child != CollectionType.UnfetchedCollection; if (reallyDoCascade) { log.Info("cascade " + action + " for collection: " + collectionType.Role); foreach (object o in action.GetCascadableChildrenIterator(eventSource, collectionType, child)) { await(CascadePropertyAsync(parent, o, elemType, style, null, anything, isCascadeDeleteEnabled, cancellationToken)).ConfigureAwait(false); } log.Info("done cascade " + action + " for collection: " + collectionType.Role); } var childAsPersColl = child as IPersistentCollection; bool deleteOrphans = style.HasOrphanDelete && action.DeleteOrphans && elemType.IsEntityType && childAsPersColl != null; //a newly instantiated collection can't have orphans if (deleteOrphans) { // handle orphaned entities!! log.Info("deleting orphans for collection: " + collectionType.Role); // we can do the cast since orphan-delete does not apply to: // 1. newly instantiated collections // 2. arrays (we can't track orphans for detached arrays) string entityName = collectionType.GetAssociatedEntityName(eventSource.Factory); await(DeleteOrphansAsync(entityName, childAsPersColl, cancellationToken)).ConfigureAwait(false); log.Info("done deleting orphans for collection: " + collectionType.Role); } }
/// <summary> /// Cascade an action to the child or children /// </summary> /// <param name="session"></param> /// <param name="child"></param> /// <param name="type"></param> /// <param name="action"></param> /// <param name="style"></param> /// <param name="cascadeTo"></param> /// <param name="anything"></param> private static void Cascade( ISessionImplementor session, object child, IType type, CascadingAction action, CascadeStyle style, CascadePoint cascadeTo, object anything) { if (child != null) { if (type.IsAssociationType) { if (((IAssociationType) type).ForeignKeyDirection.CascadeNow(cascadeTo)) { if (type.IsEntityType || type.IsAnyType) { action.Cascade(session, child, anything); } else if (type.IsCollectionType) { CascadePoint cascadeVia; if (cascadeTo == CascadePoint.CascadeAfterInsertBeforeDelete) { cascadeVia = CascadePoint.CascadeAfterInsertBeforeDeleteViaCollection; } else { cascadeVia = cascadeTo; } CollectionType pctype = (CollectionType) type; ICollectionPersister persister = session.Factory.GetCollectionPersister(pctype.Role); IType elemType = persister.ElementType; // cascade to current collection elements if (elemType.IsEntityType || elemType.IsAnyType || elemType.IsComponentType) { CascadeCollection(action, style, pctype, elemType, child, cascadeVia, session, anything); } } } } else if (type.IsComponentType) { IAbstractComponentType ctype = ((IAbstractComponentType) type); object[] children = ctype.GetPropertyValues(child, session); IType[] types = ctype.Subtypes; for (int i = 0; i < types.Length; i++) { CascadeStyle componentPropertyStyle = ctype.GetCascadeStyle(i); if (componentPropertyStyle.DoCascade(action)) { Cascade(session, children[i], types[i], action, componentPropertyStyle, cascadeTo, anything); } } } } }
/// <summary> /// Cascade to the collection elements /// </summary> /// <param name="action"></param> /// <param name="style"></param> /// <param name="collectionType"></param> /// <param name="elemType"></param> /// <param name="child"></param> /// <param name="cascadeVia"></param> /// <param name="session"></param> /// <param name="anything"></param> private static void CascadeCollection( CascadingAction action, CascadeStyle style, CollectionType collectionType, IType elemType, object child, CascadePoint cascadeVia, ISessionImplementor session, object anything) { // cascade to current collection elements if (log.IsDebugEnabled) { log.Debug("cascading to collection: " + collectionType.Role); } ICollection iter = action.CascadableChildrenCollection(collectionType, child); foreach (object obj in iter) { Cascade(session, obj, elemType, action, style, cascadeVia, anything); } // handle oprhaned entities!! if (style.HasOrphanDelete && action.DeleteOrphans() && child is IPersistentCollection) { // We can do the cast since orphan-delete does not apply to: // 1. newly instatiated collections // 2. arrays ( we can't track orphans for detached arrays) System.Type entityName = collectionType.GetAssociatedClass(session.Factory); DeleteOrphans(entityName, child as IPersistentCollection, session); } }
/// <summary> /// Get the join type (inner, outer, etc) or -1 if the /// association should not be joined. Override on /// subclasses. /// </summary> protected virtual JoinType GetJoinType(IAssociationType type, FetchMode config, string path, string lhsTable, string[] lhsColumns, bool nullable, int currentDepth, CascadeStyle cascadeStyle) { if (!IsJoinedFetchEnabled(type, config, cascadeStyle)) return JoinType.None; if (IsTooDeep(currentDepth) || (type.IsCollectionType && IsTooManyCollections)) return JoinType.None; bool dupe = IsDuplicateAssociation(lhsTable, lhsColumns, type); if (dupe) return JoinType.None; return GetJoinType(nullable, currentDepth); }
private Task CascadeAssociationAsync(object parent, object child, IType type, CascadeStyle style, object anything, bool isCascadeDeleteEnabled, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return(Task.FromCanceled <object>(cancellationToken)); } try { if (type.IsEntityType || type.IsAnyType) { return(CascadeToOneAsync(parent, child, type, style, anything, isCascadeDeleteEnabled, cancellationToken)); } else if (type.IsCollectionType) { return(CascadeCollectionAsync(parent, child, style, anything, (CollectionType)type, cancellationToken)); } return(Task.CompletedTask); } catch (System.Exception ex) { return(Task.FromException <object>(ex)); } }
/// <summary> Cascade an action to the child or children</summary> private void CascadeProperty(object child, IType type, CascadeStyle style, object anything, bool isCascadeDeleteEnabled) { if (child != null) { if (type.IsAssociationType) { IAssociationType associationType = (IAssociationType)type; if (CascadeAssociationNow(associationType)) { CascadeAssociation(child, type, style, anything, isCascadeDeleteEnabled); } } else if (type.IsComponentType) { CascadeComponent(child, (IAbstractComponentType)type, anything); } } }
/// <summary> Cascade an action to a to-one association or any type</summary> private async Task CascadeToOneAsync(object parent, object child, IType type, CascadeStyle style, object anything, bool isCascadeDeleteEnabled, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); string entityName = type.IsEntityType ? ((EntityType)type).GetAssociatedEntityName() : null; if (style.ReallyDoCascade(action)) { //not really necessary, but good for consistency... eventSource.PersistenceContext.AddChildParent(child, parent); try { await(action.CascadeAsync(eventSource, child, entityName, anything, isCascadeDeleteEnabled, cancellationToken)).ConfigureAwait(false); } finally { eventSource.PersistenceContext.RemoveChildParent(child); } } }
/// <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); } } } } } }
/// <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) { 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) { eventSource.Delete(entry.Persister.EntityName, loadedValue, false, null); } } } } } }
public MultipleCascadeStyle(CascadeStyle[] styles) { this.styles = styles; }
private void CascadeAssociation(object child, IType type, CascadeStyle style, object anything, bool isCascadeDeleteEnabled) { if (type.IsEntityType || type.IsAnyType) { CascadeToOne(child, type, style, anything, isCascadeDeleteEnabled); } else if (type.IsCollectionType) { CascadeCollection(child, style, anything, (CollectionType)type); } }
/// <summary> /// Override on subclasses to enable or suppress joining /// of certain association types /// </summary> protected virtual bool IsJoinedFetchEnabled(IAssociationType type, FetchMode config, CascadeStyle cascadeStyle) { return type.IsEntityType && IsJoinedFetchEnabledInMapping(config, type); }
protected override bool IsJoinedFetchEnabled(IAssociationType type, FetchMode config, CascadeStyle cascadeStyle) { return (type.IsEntityType || type.IsCollectionType) && (cascadeStyle == null || cascadeStyle.DoCascade(cascadeAction)); }