public void Generate(
            EntityType entityType,
            IEnumerable<EdmProperty> properties,
            EntitySetMapping entitySetMapping,
            MappingFragment entityTypeMappingFragment,
            IList<EdmProperty> propertyPath,
            bool createNewColumn)
        {
            DebugCheck.NotNull(entityType);
            DebugCheck.NotNull(properties);
            DebugCheck.NotNull(entityTypeMappingFragment);
            DebugCheck.NotNull(propertyPath);

            var rootDeclaredProperties = entityType.GetRootType().DeclaredProperties;

            foreach (var property in properties)
            {
                if (property.IsComplexType
                    && propertyPath.Any(
                        p => p.IsComplexType
                             && (p.ComplexType == property.ComplexType)))
                {
                    throw Error.CircularComplexTypeHierarchy();
                }

                propertyPath.Add(property);

                if (property.IsComplexType)
                {
                    Generate(
                        entityType,
                        property.ComplexType.Properties,
                        entitySetMapping,
                        entityTypeMappingFragment,
                        propertyPath,
                        createNewColumn);
                }
                else
                {
                    var tableColumn
                        = entitySetMapping.EntityTypeMappings
                                          .SelectMany(etm => etm.MappingFragments)
                                          .SelectMany(etmf => etmf.ColumnMappings)
                                          .Where(pm => pm.PropertyPath.SequenceEqual(propertyPath))
                                          .Select(pm => pm.ColumnProperty)
                                          .FirstOrDefault();

                    if (tableColumn == null || createNewColumn)
                    {
                        var columnName
                            = string.Join("_", propertyPath.Select(p => p.Name));

                        tableColumn
                            = MapTableColumn(
                                property,
                                columnName,
                                !rootDeclaredProperties.Contains(propertyPath.First()));

                        entityTypeMappingFragment.Table.AddColumn(tableColumn);

                        if (entityType.KeyProperties().Contains(property))
                        {
                            entityTypeMappingFragment.Table.AddKeyMember(tableColumn);
                        }
                    }

                    entityTypeMappingFragment.AddColumnMapping(
                        new ColumnMappingBuilder(tableColumn, propertyPath.ToList()));
                }

                propertyPath.Remove(property);
            }
        }
        private IEnumerable<EdmProperty> GenerateIndependentForeignKeyColumns(
            EntityType principalEntityType,
            EntityType dependentEntityType,
            AssociationSetMapping associationSetMapping,
            EndPropertyMapping associationEndMapping,
            EntityType dependentTable,
            bool isPrimaryKeyColumn,
            NavigationProperty principalNavigationProperty)
        {
            DebugCheck.NotNull(principalEntityType);
            DebugCheck.NotNull(associationEndMapping);
            DebugCheck.NotNull(dependentTable);

            foreach (var property in principalEntityType.KeyProperties())
            {
                var columnName
                    = ((principalNavigationProperty != null)
                           ? principalNavigationProperty.Name
                           : principalEntityType.Name) + "_" + property.Name;

                var foreignKeyColumn
                    = MapTableColumn(property, columnName, false);

                dependentTable.AddColumn(foreignKeyColumn);

                if (isPrimaryKeyColumn)
                {
                    dependentTable.AddKeyMember(foreignKeyColumn);
                }

                foreignKeyColumn.Nullable
                    = associationEndMapping.AssociationEnd.IsOptional()
                      || (associationEndMapping.AssociationEnd.IsRequired()
                          && dependentEntityType.BaseType != null);

                foreignKeyColumn.StoreGeneratedPattern = StoreGeneratedPattern.None;

                yield return foreignKeyColumn;

                associationEndMapping.AddPropertyMapping(new ScalarPropertyMapping(property, foreignKeyColumn));

                if (foreignKeyColumn.Nullable)
                {
                    associationSetMapping
                        .AddCondition(new IsNullConditionMapping(foreignKeyColumn, false));
                }
            }
        }
        private static bool UpdateColumnNamesForTableSharing(
            DbDatabaseMapping databaseMapping, EntityType entityType, EntityType toTable,
            StorageMappingFragment fragment)
        {
            // Validate: this table can be used only if:
            //  1. The table is not used by any other type
            //  2. The table is used only by types in the same type hierarchy (TPH)
            //  3. There is a 1:1 relationship and the PK count and types match (Table Splitting)
            var typesSharingTable = FindAllTypesUsingTable(databaseMapping, toTable);
            var associationsToSharedTable = new Dictionary<EntityType, List<AssociationType>>();

            foreach (var candidateType in typesSharingTable)
            {
                var oneToOneAssocations = FindAllOneToOneFKAssociationTypes(
                    databaseMapping.Model, entityType, candidateType);

                var rootType = candidateType.GetRootType();
                if (!associationsToSharedTable.ContainsKey(rootType))
                {
                    associationsToSharedTable.Add(rootType, oneToOneAssocations.ToList());
                }
                else
                {
                    associationsToSharedTable[rootType].AddRange(oneToOneAssocations);
                }
            }
            foreach (var candidateTypePair in associationsToSharedTable)
            {
                // Check if these types are in a TPH hierarchy
                if (candidateTypePair.Key != entityType.GetRootType()
                    && candidateTypePair.Value.Count == 0)
                {
                    var tableName = toTable.GetTableName();

                    throw Error.EntityMappingConfiguration_InvalidTableSharing(
                        entityType.Name, candidateTypePair.Key.Name,
                        tableName != null ? tableName.Name : databaseMapping.Database.GetEntitySet(toTable).Table);
                }
            }

            var allAssociations = associationsToSharedTable.Values.SelectMany(l => l);
            if (allAssociations.Any())
            {
                var principalKeyNamesType = toTable.GetKeyNamesType();
                if (principalKeyNamesType == null)
                {
                    // grab a candidate
                    var association = allAssociations.First();
                    principalKeyNamesType = association.Constraint.FromRole.GetEntityType();

                    if (allAssociations.All(x => x.Constraint.FromRole.GetEntityType() == principalKeyNamesType))
                    {
                        toTable.SetKeyNamesType(principalKeyNamesType);
                    }
                }

                // rename the columns in the fragment to match the principal keys
                var principalKeys = principalKeyNamesType.KeyProperties().ToArray();
                var i = 0;
                foreach (var k in entityType.KeyProperties())
                {
                    var dependentColumn = fragment.ColumnMappings.Single(pm => pm.PropertyPath.First() == k).ColumnProperty;
                    dependentColumn.Name = principalKeys[i].Name;
                    i++;
                }
                return true;
            }
            return false;
        }
        private HashSet<EdmPropertyPath> DiscoverAllMappingsToContain(
            DbDatabaseMapping databaseMapping, EntityType entityType, EntityType toTable,
            bool isSharingTableWithBase)
        {
            // Ensure all specified properties are the only ones present in this fragment and table
            var mappingsToContain = new HashSet<EdmPropertyPath>();

            // Include Key Properties always
            entityType.KeyProperties().Each(
                p =>
                mappingsToContain.AddRange(p.ToPropertyPathList()));

            // Include All Inherited Properties
            if (MapInheritedProperties)
            {
                entityType.Properties.Except(entityType.DeclaredProperties).Each(
                    p =>
                    mappingsToContain.AddRange(p.ToPropertyPathList()));
            }

            // If sharing table with base type, include all the mappings that the base has
            if (isSharingTableWithBase)
            {
                var baseMappingsToContain = new HashSet<EdmPropertyPath>();
                var baseType = (EntityType)entityType.BaseType;
                StorageEntityTypeMapping baseMapping = null;
                StorageMappingFragment baseFragment = null;
                // if the base is abstract it may have no mapping so look upwards until you find either:
                //   1. a type with mappings and 
                //   2. if none can be found (abstract until the root or hit another table), then include all declared properties on that base type
                while (baseType != null
                       && baseMapping == null)
                {
                    baseMapping = databaseMapping.GetEntityTypeMapping((EntityType)entityType.BaseType);
                    if (baseMapping != null)
                    {
                        baseFragment = baseMapping.MappingFragments.SingleOrDefault(tmf => tmf.Table == toTable);
                    }

                    if (baseFragment == null)
                    {
                        baseType.DeclaredProperties.Each(
                            p =>
                            baseMappingsToContain.AddRange(p.ToPropertyPathList()));
                    }

                    baseType = (EntityType)baseType.BaseType;
                }

                if (baseFragment != null)
                {
                    foreach (var pm in baseFragment.ColumnMappings)
                    {
                        mappingsToContain.Add(new EdmPropertyPath(pm.PropertyPath));
                    }
                }

                mappingsToContain.AddRange(baseMappingsToContain);
            }

            if (Properties == null)
            {
                // Include All Declared Properties
                entityType.DeclaredProperties.Each(
                    p =>
                    mappingsToContain.AddRange(p.ToPropertyPathList()));
            }
            else
            {
                // Include Specific Properties
                Properties.Each(
                    p =>
                    mappingsToContain.AddRange(PropertyPathToEdmPropertyPath(p, entityType)));
            }

            return mappingsToContain;
        }
        private StorageMappingFragment FindOrCreateTypeMappingFragment(
            DbDatabaseMapping databaseMapping,
            ref StorageEntityTypeMapping entityTypeMapping,
            int configurationIndex,
            EntityType entityType,
            DbProviderManifest providerManifest)
        {
            StorageMappingFragment fragment = null;

            if (entityTypeMapping == null)
            {
                Debug.Assert(entityType.Abstract);
                new TableMappingGenerator(providerManifest).
                    Generate(entityType, databaseMapping);
                entityTypeMapping = databaseMapping.GetEntityTypeMapping(entityType);
                configurationIndex = 0;
            }

            if (configurationIndex < entityTypeMapping.MappingFragments.Count)
            {
                fragment = entityTypeMapping.MappingFragments[configurationIndex];
            }
            else
            {
                if (MapInheritedProperties)
                {
                    throw Error.EntityMappingConfiguration_DuplicateMapInheritedProperties(entityType.Name);
                }
                else if (Properties == null)
                {
                    throw Error.EntityMappingConfiguration_DuplicateMappedProperties(entityType.Name);
                }
                else
                {
                    Properties.Each(
                        p =>
                            {
                                if (
                                    PropertyPathToEdmPropertyPath(p, entityType).Any(
                                        pp => !entityType.KeyProperties().Contains(pp.First())))
                                {
                                    throw Error.EntityMappingConfiguration_DuplicateMappedProperty(
                                        entityType.Name, p.ToString());
                                }
                            });
                }

                // Special case where they've asked for an extra table related to this type that only will include the PK columns
                // Uniquify: can be false, always move to a new table
                var templateTable = entityTypeMapping.MappingFragments[0].Table;

                var table = databaseMapping.Database.AddTable(templateTable.Name, templateTable);

                fragment
                    = EntityMappingOperations.CreateTypeMappingFragment(
                        entityTypeMapping,
                        entityTypeMapping.MappingFragments[0],
                        databaseMapping.Database.GetEntitySet(table));
            }
            return fragment;
        }
 public bool MapsAnyInheritedProperties(EntityType entityType)
 {
     var properties = new HashSet<EdmPropertyPath>();
     if (Properties != null)
     {
         Properties.Each(
             p =>
             properties.AddRange(PropertyPathToEdmPropertyPath(p, entityType)));
     }
     return MapInheritedProperties ||
            properties.Any(
                x =>
                !entityType.KeyProperties().Contains(x.First())
                && !entityType.DeclaredProperties.Contains(x.First()));
 }