Пример #1
0
        /// <summary>
        /// Calculate count of principal self navigation properties for
        /// ordering to be able to successfully define order.
        /// </summary>
        /// <remarks>
        /// If Category has principal navigation to itself named ParentCategory, we need to
        /// find count of them to be able to define order appropriately. We need to define state of
        /// them in ascending order.
        /// </remarks>
        /// <example>
        /// firstCategory which has null value on ParentCategory property has 0 principal self
        /// navigation count. If ParentCategory of secondCategory is firstCategory, then secondCategory
        /// has 1 principal self navigation count, if ParentCategory of thirdCateogry is secondCategory,
        /// then it has 2 principal self navigaiton count.
        /// </example>
        /// <typeparam name="TEntity">Type of entity.</typeparam>
        /// <param name="entity">Entity to find principla self navigaiton count.</param>
        /// <param name="store">Store to add calculated count and check first.</param>
        /// <returns>Count of principal self navigation count.</returns>
        private int CalculatePrincipalSelfNavigationCount <TEntity>(
            TEntity entity,
            Dictionary <object, int> store)
            where TEntity : class
        {
            if (store.ContainsKey(entity))
            {
                return(store[entity]);
            }

            string typeName = entity.GetType().Name;

            // Get navigation details and find properties which is refers to itslef.
            IGraphEntityManager <TEntity> entityManager          = GetEntityManager <TEntity>();
            NavigationDetail navigationDetail                    = entityManager.GetNavigationDetail();
            List <string>    selfReferringPrincipalPropertyNames = navigationDetail
                                                                   .Relations
                                                                   .Where(m => m.Direction == NavigationDirection.From &&
                                                                          m.PropertyTypeName == typeName)
                                                                   .Select(m => m.PropertyName)
                                                                   .ToList();

            // Loop through principal navigation properties and add their count.
            int principalSelfCount = 0;

            foreach (string propertyName in selfReferringPrincipalPropertyNames)
            {
                TEntity principalEntity = entity.GetPropertyValue(propertyName) as TEntity;

                // If principla entity is null then continue
                if (principalEntity == null)
                {
                    continue;
                }

                // Othewise calculate principal count as 1 + count for principal entity
                principalSelfCount++;
                principalSelfCount += CalculatePrincipalSelfNavigationCount(principalEntity, store);
            }

            store.Add(entity, principalSelfCount);
            return(principalSelfCount);
        }
Пример #2
0
        /// <summary>
        /// Add all child or parents entities related to given entity
        /// and entity itself to the relatedEntityList.
        /// </summary>
        /// <exception cref="ArgumentNullException">
        /// When entity or relatedEntityList is null.
        /// </exception>
        /// <typeparam name="TEntity">Type of entity.</typeparam>
        /// <param name="entity">Entity to get all related entities.</param>
        /// <param name="relatedEntityList">List of entities to add.</param>
        public void GetAllEntities <TEntity>(
            TEntity entity,
            List <object> relatedEntityList)
            where TEntity : class
        {
            if (entity == null)
            {
                throw new ArgumentNullException(nameof(entity));
            }

            if (relatedEntityList == null)
            {
                throw new ArgumentNullException(nameof(relatedEntityList));
            }

            if (!relatedEntityList.Contains(entity))
            {
                relatedEntityList.Add(entity);
            }

            IGraphEntityManager <TEntity> graphEntityManager = GetEntityManager <TEntity>();
            NavigationDetail navigationDetail = graphEntityManager
                                                .GetNavigationDetail();

            List <PropertyInfo> navigationPropeties = navigationDetail
                                                      .Relations
                                                      .Select(n => entity.GetProperty(n.PropertyName))
                                                      .ToList();

            if (navigationPropeties != null &&
                navigationPropeties.Count > 0)
            {
                foreach (PropertyInfo childEntityProperty in navigationPropeties)
                {
                    if (childEntityProperty.PropertyType.IsCollectionType())
                    {
                        // If child entity is collection get all entities inside this collection.
                        IEnumerable <object> enumerableChildEntity =
                            entity.GetPropertyValue(childEntityProperty.Name) as IEnumerable <object>;

                        if (enumerableChildEntity != null)
                        {
                            for (int i = 0; i < enumerableChildEntity.Count(); i++)
                            {
                                dynamic childEntity = enumerableChildEntity.ElementAt(i);
                                if (childEntity != null &&
                                    !relatedEntityList.Contains(childEntity))
                                {
                                    GetAllEntities(
                                        childEntity,
                                        relatedEntityList);
                                }
                            }
                        }
                    }
                    else
                    {
                        // If child entity is not collection get its own.
                        dynamic childEntity = entity.GetPropertyValue(childEntityProperty.Name);

                        if (childEntity != null &&
                            !relatedEntityList.Contains(childEntity))
                        {
                            GetAllEntities(
                                childEntity,
                                relatedEntityList);
                        }
                    }
                }
            }
        }
Пример #3
0
        /// <summary>
        /// Set property of parent entity to targetValue
        /// which has property value equals to currentValue.
        /// </summary>
        /// <typeparam name="TEntity">Type of entity.</typeparam>
        /// <param name="currentValue">Current value of property to replace.</param>
        /// <param name="targetValue">Target value to set value of property of parent.</param>
        private void ReplaceEntitiesInParents <TEntity>(
            TEntity currentValue,
            TEntity targetValue)
            where TEntity : class
        {
            IGraphEntityManager <TEntity> graphEntityManager = GetEntityManager <TEntity>();
            NavigationDetail navigationDetailOfCurrent       = graphEntityManager
                                                               .GetNavigationDetail();

            // Get parent properties of entity.
            // Properties which have navigation property type of which
            // is type of entity. Ignore navigation properties
            // which are mutual navigation properties with entity itself.
            string typeName = currentValue.GetType().Name;
            List <NavigationDetail> parentNavigationDetails = GetNavigationDetails()
                                                              .Select(n => new NavigationDetail()
            {
                SourceTypeName = n.SourceTypeName,
                Relations      = n.Relations
                                 .Where(r => r.PropertyTypeName.Equals(typeName) &&
                                        r.SourceMultiplicity == RelationshipMultiplicity.Many &&
                                        !navigationDetailOfCurrent
                                        .Relations
                                        .Any(c => c.PropertyTypeName.Equals(n.SourceTypeName) &&
                                             c.TargetMultiplicity == r.SourceMultiplicity &&
                                             c.FromKeyNames.SequenceEqual(r.FromKeyNames) &&
                                             c.ToKeyNames.SequenceEqual(r.ToKeyNames)))
                                 .ToList()
            })
                                                              .Where(n => n.Relations != null &&
                                                                     n.Relations.Count() > 0)
                                                              .ToList();

            // Get assembly to be able to get types according to type name
            Assembly entityAssembly = currentValue.GetType().Assembly;

            if (parentNavigationDetails != null && parentNavigationDetails.Count() > 0)
            {
                foreach (NavigationDetail parentNavigation in parentNavigationDetails)
                {
                    Type parentType = entityAssembly.GetTypes()
                                      .FirstOrDefault(t => t.Name.Equals(parentNavigation.SourceTypeName));

                    // Get local set of parent
                    IEnumerable <object> localParentSet = Context
                                                          .Set(parentType)
                                                          .Local
                                                          .CastToGeneric();

                    foreach (NavigationRelation navigationRelation in parentNavigation.Relations)
                    {
                        PropertyInfo childProperty =
                            parentType.GetProperty(navigationRelation.PropertyName);

                        if (!childProperty.PropertyType.IsCollectionType())
                        {
                            // Get all parent entities which have current entity inside
                            var containerParentCollection = localParentSet
                                                            .Where(m => m.GetPropertyValue(navigationRelation.PropertyName) != null &&
                                                                   m.GetPropertyValue(navigationRelation.PropertyName).Equals(currentValue))
                                                            .ToList();

                            // If collection is empty then skip.
                            if (containerParentCollection == null ||
                                containerParentCollection.Count == 0)
                            {
                                continue;
                            }

                            foreach (var containerParent in containerParentCollection)
                            {
                                // If parent is null then skip.
                                if (containerParent == null)
                                {
                                    continue;
                                }

                                // If parent with property value of currentValue found replace values

                                /*
                                 * If duplicate entity is in the entity, state of which has already
                                 * been defined and if state of this parent entity is Unchanged or
                                 * Modified, trying to change navigation property of this parent entity
                                 * will throw InvalidOperationException with following message:
                                 * "A referential integrity constraint violation occurred:
                                 *  A primary key property that is a part of referential integrity constraint
                                 *  cannot be changed when the dependent object is Unchanged unless it is being
                                 *  set to the association's principal object. The principal object must
                                 *  be tracked and not marked for deletion."
                                 * As a workaround I am storing current state of parent entity, changing the
                                 * state to Added, then replacing duplicate entity and in the end
                                 * I set state of parent entity to stored current state.
                                 */

                                // Store current state
                                var currentState = Context.Entry(containerParent).State;
                                // Change state to added
                                Context.Entry(containerParent).State = EntityState.Added;

                                // Replace value through
                                // context.Entry(containerParent).Member(propertyName).CurrentValue
                                // because otherwise EntityFramework will not be able to track entities
                                Context.Entry(containerParent)
                                .Member(navigationRelation.PropertyName).CurrentValue = targetValue;

                                // Restore state to current state
                                Context.Entry(containerParent).State = currentState;
                            }
                        }
                    }
                }
            }
        }