/// <summary>
        /// Loads the navigation collection.
        /// </summary>
        /// <param name="entityEntry">The entity entry.</param>
        /// <param name="navigation">The navigation.</param>
        /// <param name="context">The context.</param>
        protected virtual void LoadCollection(EntityEntry entityEntry, INavigation navigation, DbContext context)
        {
            var foreignKeyProperty = navigation.ForeignKey.Properties.First();
            var loadStatusAware    = navigation.GetGetter().GetClrValue(entityEntry.Entity) as ILoadingStatusAwareList;

            if (loadStatusAware?.LoadingStatus == LoadingStatus.Loaded || loadStatusAware?.LoadingStatus == LoadingStatus.Loading)
            {
                // already loaded or loading
                return;
            }

            if (loadStatusAware == null && navigation.GetGetter().GetClrValue(entityEntry.Entity) != null)
            {
                // already loaded or loading
                return;
            }

            if (loadStatusAware == null)
            {
                throw new InvalidOperationException($"The collection is not implementing {nameof(ILoadingStatusAware)}");
            }

            loadStatusAware.LoadingStatus = LoadingStatus.Loading;

            if (this.repositoryManager.GetRepository(foreignKeyProperty.DeclaringEntityType.ClrType) is ILoadByProperty repository)
            {
                var foreignKeyValue = entityEntry.Property(navigation.ForeignKey.PrincipalKey.Properties.First().Name).CurrentValue;
                var items           = repository.LoadByProperty(foreignKeyProperty, foreignKeyValue);
                foreach (var obj in items)
                {
                    if (!loadStatusAware.Contains(obj))
                    {
                        loadStatusAware.Add(obj);
                    }
                }

                loadStatusAware.LoadingStatus = LoadingStatus.Loaded;
            }
            else
            {
                Log.Warn($"No repository found which supports loading by foreign key for type ${foreignKeyProperty.DeclaringEntityType.ClrType}.");
                loadStatusAware.LoadingStatus = LoadingStatus.Failed;
            }
        }
Exemple #2
0
        /// <summary>
        /// Loads the data navigation property and sets it in the entity.
        /// </summary>
        /// <param name="entityEntry">The entity entry from the context.</param>
        /// <param name="navigation">The navigation property.</param>
        protected virtual void LoadNavigationProperty(EntityEntry entityEntry, INavigation navigation)
        {
            if (navigation.ForeignKey.DeclaringEntityType != navigation.DeclaringEntityType)
            {
                // inverse property
                return;
            }

            var keyProperty = navigation.ForeignKey.Properties.First();
            var idValue     = entityEntry.Property(keyProperty.Name).CurrentValue;

            Guid id = (idValue as Guid?) ?? Guid.Empty;

            if (id != Guid.Empty)
            {
                var getter       = navigation.GetGetter();
                var currentValue = getter.GetClrValue(entityEntry.Entity);
                if ((currentValue is IIdentifiable) && (currentValue as IIdentifiable).Id == id)
                {
                    // loaded already
                    return;
                }

                IRepository repository = null;
                try
                {
                    repository = this.RepositoryManager.GetRepository(navigation.GetTargetType().ClrType);
                }
                catch (RepositoryNotFoundException ex)
                {
                    this.logger.LogError(ex, $"Repository not found: {ex.Message}");
                }

                if (repository != null)
                {
#pragma warning disable EF1001 // Internal EF Core API usage.
                    if (navigation is Navigation concreteNavigation &&
                        concreteNavigation.Setter != null)
                    {
                        concreteNavigation.Setter.SetClrValue(entityEntry.Entity, repository.GetById(id));
                    }
                    else
                    {
                        this.logger.LogError($"Could not find setter for navigation {navigation}");
                    }
#pragma warning restore EF1001 // Internal EF Core API usage.
                }
                else
                {
                    this.logger.LogError($"Repository not found for navigation target type {navigation.GetTargetType()}.");
                }
            }
        private static void FixupNavigation(INavigation navigation, object entity, object cached)
        {
            var value = navigation.GetGetter().GetClrValue(entity);

            if (value == null)
            {
                return;
            }

            if (navigation.FieldInfo != null)
            {
                navigation.FieldInfo.SetValue(cached, value);
            }
            else
            {
                navigation.GetSetter().SetClrValue(cached, value);
            }

            var inverse = navigation.FindInverse();

            if (inverse == null)
            {
                return;
            }

            if (inverse.IsCollection())
            {
                var collection = inverse.GetCollectionAccessor();

                collection.Add(value, cached);
            }
            else
            {
                var setter = inverse.GetSetter();

                if (value is IEnumerable enumerable)
                {
                    foreach (var item in enumerable)
                    {
                        setter.SetClrValue(item, cached);
                    }
                }
                else
                {
                    setter.SetClrValue(value, cached);
                }
            }
        }
        void InitializeKeyGetters()
        {
            _keyGetters = new List <IKeyGetter>();
            HashSet <Property> visited = new HashSet <Property>();

            foreach (Property property in _key.Properties)
            {
                if (property.IsForeignKey())
                {
                    if (!visited.Contains(property))
                    {
                        IEnumerable <ForeignKey> foreignKeys = property.GetContainingForeignKeys();
                        if (foreignKeys.Count() != 1)
                        {
                            throw new Exception("not supported");
                        }

                        ForeignKey foreignKey = foreignKeys.First();
                        foreach (Property prop in foreignKey.Properties)
                        {
                            visited.Add(prop);
                        }

                        INavigation navigation = foreignKey.GetNavigations()
                                                 .Where(n => n.DeclaringEntityType.ClrType == _entityType.ClrType)
                                                 .Single();

                        IEntityType fkType = navigation.GetTargetType();
                        IKey        fkKey  = fkType.FindPrimaryKey();

                        List <IClrPropertyGetter> fkKeyGetters = new List <IClrPropertyGetter>();
                        foreach (Property fkKeyProperty in fkKey.Properties)
                        {
                            fkKeyGetters.Add(fkKeyProperty.GetGetter());
                            _keySize++;
                        }
                        _keyGetters.Add(new ForeignKeyGetter(navigation.GetGetter(), fkKeyGetters));
                    }
                }
                else
                {
                    visited.Add(property);
                    _keyGetters.Add(new SimpleKeyGetter(property.GetGetter()));
                    _keySize++;
                }
            }
        }
        /// <summary>
        /// Loads the data navigation property and sets it in the entity.
        /// </summary>
        /// <param name="entityEntry">The entity entry from the context.</param>
        /// <param name="navigation">The navigation property.</param>
        protected virtual void LoadNavigationProperty(EntityEntry entityEntry, INavigation navigation)
        {
            if (navigation.ForeignKey.DeclaringEntityType != navigation.DeclaringEntityType)
            {
                // inverse property
                return;
            }

            var keyProperty = navigation.ForeignKey.Properties.First();
            var idValue     = entityEntry.Property(keyProperty.Name).CurrentValue;

            Guid id = (idValue as Guid?) ?? Guid.Empty;

            if (id != Guid.Empty)
            {
                var getter       = navigation.GetGetter();
                var currentValue = getter.GetClrValue(entityEntry.Entity);
                if ((currentValue is IIdentifiable) && (currentValue as IIdentifiable).Id == id)
                {
                    // loaded already
                    return;
                }

                IRepository repository = null;
                try
                {
                    repository = this.contextProvider.RepositoryManager.GetRepository(navigation.GetTargetType().ClrType);
                }
                catch (RepositoryNotFoundException ex)
                {
                    Log.Error($"Repository not found: {ex.Message}");
                }

                if (repository != null)
                {
                    var setter = navigation.GetSetter();
                    setter.SetClrValue(entityEntry.Entity, repository.GetById(id));
                }
                else
                {
                    Log.Error($"Repository not found for navigation target type {navigation.GetTargetType()}.");
                }
            }
        }
        private static object TryFindPrincipal(IStateManager stateManager, INavigation navigation, object dependentEntity)
        {
            if (navigation.IsDependentToPrincipal())
            {
                return navigation.GetGetter().GetClrValue(dependentEntity);
            }

            // TODO: Perf
            foreach (var principalEntry in stateManager.Entries.Where(
                e => e.EntityState != EntityState.Detached
                     && navigation.ForeignKey.PrincipalEntityType.IsAssignableFrom(e.EntityType)))
            {
                if (navigation.IsCollection())
                {
                    if (navigation.GetCollectionAccessor().Contains(principalEntry.Entity, dependentEntity))
                    {
                        return principalEntry.Entity;
                    }
                }
                else if (navigation.GetGetter().GetClrValue(principalEntry.Entity) == dependentEntity)
                {
                    return principalEntry.Entity;
                }
            }

            return null;
        }