Exemplo n.º 1
0
        /// <summary>
        /// Get the the origin class which this foreign key refers to.
        /// </summary>
        /// <exception cref="ArgumentNullException">
        /// When foreignKeyName is null.
        /// </exception>
        /// <param name="foreignKeyName">Name of foreign key property.</param>
        /// <returns>Name of class which this foreign key refers to.</returns>
        public string GetOriginOfForeignKey(string foreignKeyName)
        {
            if (string.IsNullOrEmpty(foreignKeyName))
            {
                throw new ArgumentNullException(nameof(foreignKeyName));
            }

            // Try to get from store
            Tuple <string, string> key = new Tuple <string, string>(EntityTypeName, foreignKeyName);

            if (Store.ForeignKeyOrigin.ContainsKey(key))
            {
                return(Store.ForeignKeyOrigin[key]);
            }

            string originOfForeignKey = string.Empty;

            // Principal relationship multiplicities
            List <RelationshipMultiplicity> principalRelationshipMultiplicity =
                new List <RelationshipMultiplicity>()
            {
                RelationshipMultiplicity.One,
                RelationshipMultiplicity.ZeroOrOne
            };

            // Get the relationship detail which this foreign keys refers.
            RelationshipDetail parentType = GetForeignKeyDetails()
                                            .Where(r => r.ToDetails.ContainerClass.Equals(EntityTypeName) &&
                                                   r.ToDetails.Keys.Any(k => k.Equals(foreignKeyName)) &&
                                                   r.FromDetails != null &&
                                                   !string.IsNullOrEmpty(r.FromDetails.ContainerClass) &&
                                                   principalRelationshipMultiplicity
                                                   .Contains(r.FromDetails.RelationshipMultiplicity))
                                            .FirstOrDefault();

            if (parentType != null)
            {
                var currentReferencedTypeName = parentType.FromDetails.ContainerClass;
                var currentForeignKeyName     = GetMatchingFromForeignKeyName(parentType, foreignKeyName);
                while (!string.IsNullOrEmpty(currentReferencedTypeName))
                {
                    // If EntityTypeName and currentReferencedTypeName is same,
                    // then this is self reference, so we need to break infinete iteration.
                    if (EntityTypeName == currentReferencedTypeName)
                    {
                        break;
                    }

                    IGraphEntityTypeManager referencedTypeManager = ContextFactory
                                                                    .GetEntityTypeManager(currentReferencedTypeName);

                    // Get one-to-one principal parent relationship detail,
                    // because the origin of foreign key is uppermost principal parent.
                    RelationshipDetail principalParent = referencedTypeManager
                                                         .GetForeignKeyDetails()
                                                         .Where(r => r.ToDetails.ContainerClass.Equals(currentReferencedTypeName) &&
                                                                r.ToDetails.Keys.Contains(currentForeignKeyName) &&
                                                                r.FromDetails != null &&
                                                                !string.IsNullOrEmpty(r.FromDetails.ContainerClass) &&
                                                                principalRelationshipMultiplicity
                                                                .Contains(r.FromDetails.RelationshipMultiplicity))
                                                         .FirstOrDefault();

                    if (principalParent != null)
                    {
                        // If principal parent is not null set current to this.
                        currentReferencedTypeName = principalParent.FromDetails.ContainerClass;
                        currentForeignKeyName     = GetMatchingFromForeignKeyName(principalParent, currentForeignKeyName);
                    }
                    else
                    {
                        // If principal parent is null exit the iteration.
                        break;
                    }
                }

                originOfForeignKey = currentReferencedTypeName;
            }

            // Add to store
            Store.ForeignKeyOrigin.Add(key, originOfForeignKey);
            return(originOfForeignKey);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Detach dependants of entity.
        /// </summary>
        /// <exception cref="ArgumentNullException">
        /// When  entity is null
        /// </exception>
        /// <typeparam name="TEntity">Type of entity.</typeparam>
        /// <param name="entity">Entity to detach dependants.</param>
        /// <param name="detachItself">Also detach entity itself.</param>
        public void DetachWithDependants <TEntity>(
            TEntity entity,
            bool detachItself)
            where TEntity : class
        {
            if (entity == null)
            {
                throw new ArgumentNullException(nameof(entity));
            }

            string typeName = entity.GetType().Name;
            IGraphEntityTypeManager graphEntityTypeManager =
                GetEntityTypeManager(typeName);
            List <string> dependantPropertyTypes = graphEntityTypeManager
                                                   .GetForeignKeyDetails()
                                                   .Where(r => r.FromDetails
                                                          .ContainerClass
                                                          .Equals(typeName))
                                                   .Select(r => r.ToDetails.ContainerClass)
                                                   .ToList();

            List <PropertyInfo> dependantProperties = entity
                                                      .GetType()
                                                      .GetProperties()
                                                      .Where(p => dependantPropertyTypes
                                                             .Contains(p.PropertyType.GetUnderlyingType().Name))
                                                      .ToList();

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

                        if (enumerableChildEntity != null)
                        {
                            foreach (dynamic childEntity in enumerableChildEntity.ToList())
                            {
                                if (childEntity != null)
                                {
                                    DetachWithDependants(childEntity, true);
                                }
                            }
                        }
                    }
                    else
                    {
                        // If child entity is not collection define state of its own
                        dynamic childEntity =
                            ReflectionExtensions.GetPropertyValue(entity, childEntityProperty.Name);

                        if (childEntity != null)
                        {
                            DetachWithDependants(childEntity, true);
                        }
                    }
                }
            }

            if (detachItself)
            {
                Context.Entry(entity).State = EntityState.Detached;
            }
        }
        /// <summary>
        /// Construct filter expression for entity.
        /// </summary>
        /// <param name="entity">Entity to construct filter expression for.</param>
        /// <param name="typeOfFilter">Type of filter expression.</param>
        /// <returns>Filter expression according to entity.</returns>
        public Expression <Func <TEntity, bool> > ConstructFilterExpression(
            TEntity entity,
            FilterType typeOfFilter)
        {
            Expression <Func <TEntity, bool> > filterExpression = null;
            IEnumerable <string> primaryKeyNames = GetPrimaryKeys();

            if (primaryKeyNames.Count() == 0)
            {
                throw new ArgumentException(string.Format(
                                                "'{0}' has no configured primary key.",
                                                typeof(TEntity).Name));
            }

            List <Expression>        equalityExpressions = new List <Expression>();
            IEnumerable <Expression> singleExpressionList;

            ParameterExpression parameterExp = Expression.Parameter(typeof(TEntity), "m");
            Expression          pkFilter     = null;
            Expression          ukFilter     = null;

            bool primaryKeysHaveDefaultValues = entity.HasDefaultValues(primaryKeyNames);

            if (!primaryKeysHaveDefaultValues &&
                typeOfFilter != FilterType.OnlyUnique)
            {
                // If primary keys do not have their default values
                // add this check to equlity expression list
                singleExpressionList = parameterExp
                                       .ConstructEqualityExpressions(
                    entity,
                    primaryKeyNames);

                pkFilter = singleExpressionList.ConstructAndChain();
            }

            if (typeOfFilter != FilterType.OnlyId &&
                (primaryKeysHaveDefaultValues ||
                 typeOfFilter != FilterType.IdOptionalUnique))
            {
                IEnumerable <PropertiesWithSource> uniqueProperties =
                    MappingStorage.Instance.UniqueProperties.Where(
                        m => m.SourceType.Equals(entity.GetType()));

                if (uniqueProperties.Count() > 0)
                {
                    foreach (PropertiesWithSource unique in uniqueProperties)
                    {
                        /*
                         ***********************************************************
                         * If any of current set of properties
                         * marked as unique is foreign key,
                         * has default value, and appropriate navigation property is not
                         * null and also origin of this foreign
                         * key has any store generated primary key then this
                         * uniqueness must be ignored.
                         * For example if PersonId (int) and DocumentType (short) has been
                         * set as composite unique in PersonDocument and
                         * if PersonId is foreign key to Person, which in its term has
                         * Primary key which is store generated and if there is no navigation
                         * property to Person from PersonDocument or PersonDocument.Person is not null
                         * then PersonId = 0 and DocumentType = 5 should not
                         * be treated as unique, because the real value of PersonId
                         * will be computed when data will be inserted.
                         ***********************************************************
                         */

                        IGraphEntityTypeManager uniqueSourceTypeManager = ContextFactory
                                                                          .GetEntityTypeManager(unique.SourceType.Name);

                        bool uniquenessMustBeIgnored = false;

                        var uniquePropertyNames = unique.Properties.Select(m => m.Name).ToList();
                        var uniqueForeignKeys   = uniqueSourceTypeManager
                                                  .GetForeignKeyDetails()
                                                  .Select(m => new
                        {
                            TargetClass = m.FromDetails.ContainerClass,
                            Keys        = m.ToDetails.Keys.Intersect(uniquePropertyNames)
                        })
                                                  .Where(m => m.Keys != null &&
                                                         m.Keys.Any());

                        NavigationDetail navigationDetailsOfCurrent = GetNavigationDetail();

                        // If unuque property is foreign key
                        if (uniqueForeignKeys != null &&
                            uniqueForeignKeys.Any())
                        {
                            foreach (var uniqueFk in uniqueForeignKeys)
                            {
                                // If foreign key has default value
                                if (uniqueFk.Keys.Any(u => entity.HasDefaultValue(u)))
                                {
                                    // Get navigation relation according to foreign key
                                    NavigationRelation navigationRelation = navigationDetailsOfCurrent
                                                                            .Relations
                                                                            .FirstOrDefault(r => r.Direction == NavigationDirection.From &&
                                                                                            r.PropertyTypeName.Equals(uniqueFk.TargetClass) &&
                                                                                            r.ToKeyNames.Intersect(uniqueFk.Keys).Any());

                                    // If corresponding navigation property is not null
                                    // or there is no such navigation property
                                    if (navigationRelation == null ||
                                        entity.GetPropertyValue(navigationRelation.PropertyName) != null)
                                    {
                                        bool foreignKeyHasStoreGeneratedPrimaryKey =
                                            uniqueFk.Keys.Any(k =>
                                        {
                                            // Get origin of foreign key and check
                                            // if it has store generated key.
                                            string foreignKeyOrigin = uniqueSourceTypeManager
                                                                      .GetOriginOfForeignKey(k);
                                            IGraphEntityTypeManager foreignKeyOriginTypeManger = ContextFactory
                                                                                                 .GetEntityTypeManager(foreignKeyOrigin);
                                            return(foreignKeyOriginTypeManger.HasStoreGeneratedKey());
                                        });

                                        // If origin of foreign key has store generated Primary key
                                        if (foreignKeyHasStoreGeneratedPrimaryKey)
                                        {
                                            uniquenessMustBeIgnored = true;
                                            break;
                                        }
                                    }
                                }
                            }
                        }

                        // If uniqueness must be ignored then skip this iteration
                        if (uniquenessMustBeIgnored)
                        {
                            continue;
                        }

                        singleExpressionList = parameterExp
                                               .ConstructEqualityExpressions(
                            entity,
                            unique.Properties
                            .Select(m => m.Name).ToList());
                        equalityExpressions.Add(singleExpressionList.ConstructAndChain());
                    }

                    if (equalityExpressions.Count > 0)
                    {
                        ukFilter = equalityExpressions.ConstructOrChain();
                    }
                }
            }

            equalityExpressions.Clear();
            if (pkFilter != null)
            {
                equalityExpressions.Add(pkFilter);
            }

            if (ukFilter != null)
            {
                equalityExpressions.Add(ukFilter);
            }

            if (equalityExpressions.Count > 0)
            {
                Expression filterBaseExpression = typeOfFilter == FilterType.IdAndUnique
                    ? equalityExpressions.ConstructAndChain()
                    : equalityExpressions.ConstructOrChain();

                filterExpression = Expression.Lambda <Func <TEntity, bool> >(
                    filterBaseExpression, parameterExp);
            }

            return(filterExpression);
        }