protected internal async Task <object> GetReferenceValueAsync(object value, ISessionImplementor session, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            if (value == null)
            {
                return(null);
            }
            else if (IsReferenceToPrimaryKey)
            {
                return(await(ForeignKeys.GetEntityIdentifierIfNotUnsavedAsync(GetAssociatedEntityName(), value, session, cancellationToken)).ConfigureAwait(false));                 //tolerates nulls
            }
            else
            {
                IEntityPersister entityPersister = session.Factory.GetEntityPersister(GetAssociatedEntityName());
                object           propertyValue   = entityPersister.GetPropertyValue(value, uniqueKeyPropertyName);

                // We now have the value of the property-ref we reference.  However,
                // we need to dig a little deeper, as that property might also be
                // an entity type, in which case we need to resolve its identitifier
                IType type = entityPersister.GetPropertyType(uniqueKeyPropertyName);
                if (type.IsEntityType)
                {
                    propertyValue = await(((EntityType)type).GetReferenceValueAsync(propertyValue, session, cancellationToken)).ConfigureAwait(false);
                }

                return(propertyValue);
            }
        }
        protected internal object GetReferenceValue(object value, ISessionImplementor session)
        {
            if (value == null)
            {
                return(null);
            }
            else if (IsReferenceToPrimaryKey)
            {
                return(ForeignKeys.GetEntityIdentifierIfNotUnsaved(GetAssociatedEntityName(), value, session));                //tolerates nulls
            }
            else
            {
                IEntityPersister entityPersister = session.Factory.GetEntityPersister(GetAssociatedEntityName());
                object           propertyValue   = entityPersister.GetPropertyValue(value, uniqueKeyPropertyName);

                // We now have the value of the property-ref we reference.  However,
                // we need to dig a little deeper, as that property might also be
                // an entity type, in which case we need to resolve its identitifier
                IType type = entityPersister.GetPropertyType(uniqueKeyPropertyName);
                if (type.IsEntityType)
                {
                    propertyValue = ((EntityType)type).GetReferenceValue(propertyValue, session);
                }

                return(propertyValue);
            }
        }
Exemple #3
0
        private async Task <object> MergeTransientEntityAsync(object entity, string entityName, object requestedId, IEventSource source, IDictionary copyCache, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            IEntityPersister persister = source.GetEntityPersister(entityName, entity);

            object id   = persister.HasIdentifierProperty ? persister.GetIdentifier(entity) : null;
            object copy = null;

            if (copyCache.Contains(entity))
            {
                copy = copyCache[entity];
                persister.SetIdentifier(copy, id);
            }
            else
            {
                copy = source.Instantiate(persister, id);
                ((EventCache)copyCache).Add(entity, copy, true);                 // before cascade!
            }

            // cascade first, so that all unsaved objects get their
            // copy created before we actually copy
            //cascadeOnMerge(event, persister, entity, copyCache, Cascades.CASCADE_BEFORE_MERGE);
            await(base.CascadeBeforeSaveAsync(source, persister, entity, copyCache, cancellationToken)).ConfigureAwait(false);
            await(CopyValuesAsync(persister, entity, copy, source, copyCache, ForeignKeyDirection.ForeignKeyFromParent, cancellationToken)).ConfigureAwait(false);

            try
            {
                // try saving; check for non-nullable properties that are null or transient entities before saving
                await(this.SaveTransientEntityAsync(copy, entityName, requestedId, source, copyCache, cancellationToken)).ConfigureAwait(false);
            }
            catch (PropertyValueException ex)
            {
                string      propertyName       = ex.PropertyName;
                object      propertyFromCopy   = persister.GetPropertyValue(copy, propertyName);
                object      propertyFromEntity = persister.GetPropertyValue(entity, propertyName);
                IType       propertyType       = persister.GetPropertyType(propertyName);
                EntityEntry copyEntry          = source.PersistenceContext.GetEntry(copy);

                if (propertyFromCopy == null || !propertyType.IsEntityType)
                {
                    log.Info("property '{0}.{1}' is null or not an entity; {1} =[{2}]", copyEntry.EntityName, propertyName, propertyFromCopy);
                    throw;
                }

                if (!copyCache.Contains(propertyFromEntity))
                {
                    log.Info("property '{0}.{1}' from original entity is not in copyCache; {1} =[{2}]", copyEntry.EntityName, propertyName, propertyFromEntity);
                    throw;
                }

                if (((EventCache)copyCache).IsOperatedOn(propertyFromEntity))
                {
                    log.Info(ex, "property '{0}.{1}' from original entity is in copyCache and is in the process of being merged; {1} =[{2}]", copyEntry.EntityName, propertyName, propertyFromEntity);
                }
                else
                {
                    log.Info(ex, "property '{0}.{1}' from original entity is in copyCache and is not in the process of being merged; {1} =[{2}]", copyEntry.EntityName, propertyName, propertyFromEntity);
                }

                // continue...; we'll find out if it ends up not getting saved later
            }

            // cascade first, so that all unsaved objects get their
            // copy created before we actually copy
            await(base.CascadeAfterSaveAsync(source, persister, entity, copyCache, cancellationToken)).ConfigureAwait(false);
            await(CopyValuesAsync(persister, entity, copy, source, copyCache, ForeignKeyDirection.ForeignKeyToParent, cancellationToken)).ConfigureAwait(false);

            return(copy);
        }