private static bool RemapsInheritedProperties(
            DbDatabaseMapping databaseMapping, DbEntityTypeMapping entityTypeMapping)
        {
            var inheritedProperties = entityTypeMapping.EntityType.Properties
                .Except(entityTypeMapping.EntityType.DeclaredProperties)
                .Except(entityTypeMapping.EntityType.GetKeyProperties());

            foreach (var property in inheritedProperties)
            {
                var fragment = GetFragmentForPropertyMapping(entityTypeMapping, property);

                if (fragment != null)
                {
                    // find if this inherited property is mapped to another table by a base type
                    var baseType = entityTypeMapping.EntityType.BaseType;
                    while (baseType != null)
                    {
                        if (databaseMapping.GetEntityTypeMappings(baseType)
                            .Select(baseTypeMapping => GetFragmentForPropertyMapping(baseTypeMapping, property))
                            .Any(
                                baseFragment => baseFragment != null
                                                && baseFragment.Table != fragment.Table))
                        {
                            return true;
                        }
                        baseType = baseType.BaseType;
                    }
                }
            }
            return false;
        }
        public void Configure_should_update_table_name_when_base_type_is_null()
        {
            var entityMappingConfiguration = new EntityMappingConfiguration
                                                 {
                                                     TableName = new DatabaseName("Foo")
                                                 };
            var entityTypeMapping = new DbEntityTypeMapping
                                        {
                                            EntityType = new EdmEntityType()
                                        };
            var table = new DbTableMetadata
                            {
                                Name = "foo"
                            };
            entityTypeMapping.TypeMappingFragments.Add(
                new DbEntityTypeMappingFragment
                    {
                        Table = table
                    });

            var databaseMapping =
                new DbDatabaseMapping().Initialize(new EdmModel().Initialize(), new DbDatabaseMetadata().Initialize());
            databaseMapping.Database.AddTable("foo");
            entityMappingConfiguration.Configure(
                databaseMapping, ProviderRegistry.Sql2008_ProviderManifest, entityTypeMapping.EntityType, ref entityTypeMapping, false, 0, 1);

            Assert.Equal("Foo", table.GetTableName().Name);
        }
        public static DbEntityTypeMapping Clone(this DbEntityTypeMapping entityTypeMappping)
        {
            //Contract.Requires(entityTypeMappping != null);

            var clone = new DbEntityTypeMapping
                {
                    EntityType = entityTypeMappping.EntityType
                };
            entityTypeMappping.Annotations.Copy(clone.Annotations);

            return clone;
        }
        public void GetPropertyMapping_should_return_mapping_with_path()
        {
            var entityTypeMapping = new DbEntityTypeMapping();
            var propertyFoo = new EdmProperty { Name = "Foo" };
            var propertyBar = new EdmProperty { Name = "Bar" };
            var entityPropertyMapping = new DbEdmPropertyMapping
                {
                    PropertyPath = new[]
                        {
                            propertyFoo,
                            propertyBar,
                        }
                };

            var entityTypeMappingFragment = new DbEntityTypeMappingFragment();
            entityTypeMappingFragment.PropertyMappings.Add(entityPropertyMapping);
            entityTypeMapping.TypeMappingFragments.Add(entityTypeMappingFragment);

            Assert.Same(entityPropertyMapping, entityTypeMapping.GetPropertyMapping(propertyFoo, propertyBar));
        }
        public void Generate(EdmEntityType entityType, DbDatabaseMapping databaseMapping)
        {
            //Contract.Requires(entityType != null);
            //Contract.Requires(databaseMapping != null);

            var entitySet = databaseMapping.Model.GetEntitySet(entityType);

            var entitySetMapping
                = databaseMapping.GetEntitySetMapping(entitySet)
                  ?? databaseMapping.AddEntitySetMapping(entitySet);

            var table
                = entitySetMapping.EntityTypeMappings.Any()
                      ? entitySetMapping.EntityTypeMappings.First().TypeMappingFragments.First().Table
                      : databaseMapping.Database.AddTable(entityType.GetRootType().Name);

            var entityTypeMappingFragment = new DbEntityTypeMappingFragment
                {
                    Table = table
                };

            var entityTypeMapping = new DbEntityTypeMapping
                {
                    EntityType = entityType,
                    IsHierarchyMapping = false
                };
            entityTypeMapping.TypeMappingFragments.Add(entityTypeMappingFragment);
            entityTypeMapping.SetClrType(entityType.GetClrType());

            entitySetMapping.EntityTypeMappings.Add(entityTypeMapping);

            new PropertyMappingGenerator(_providerManifest)
                .Generate(
                    entityType,
                    entityType.Properties,
                    entitySetMapping,
                    entityTypeMappingFragment,
                    new List<EdmProperty>(),
                    false);
        }
        public void GetComplexPropertyMappings_should_return_all_complex_property_mappings_for_type()
        {
            var databaseMapping = new DbDatabaseMapping()
                .Initialize(new EdmModel().Initialize(), new DbDatabaseMetadata());
            var entitySet = new EdmEntitySet();
            var entitySetMapping = databaseMapping.AddEntitySetMapping(entitySet);
            var entityTypeMapping = new DbEntityTypeMapping();
            entitySetMapping.EntityTypeMappings.Add(entityTypeMapping);
            var entityTypeMappingFragment = new DbEntityTypeMappingFragment();
            entityTypeMapping.TypeMappingFragments.Add(entityTypeMappingFragment);
            var propertyMapping1 = new DbEdmPropertyMapping();
            var complexType = new EdmComplexType();
            complexType.SetClrType(typeof(object));
            propertyMapping1.PropertyPath.Add(new EdmProperty { PropertyType = new EdmTypeReference { EdmType = complexType } });
            entityTypeMappingFragment.PropertyMappings.Add(propertyMapping1);
            var propertyMapping2 = new DbEdmPropertyMapping();
            propertyMapping2.PropertyPath.Add(new EdmProperty { PropertyType = new EdmTypeReference() });
            propertyMapping2.PropertyPath.Add(new EdmProperty { PropertyType = new EdmTypeReference { EdmType = complexType } });
            entityTypeMappingFragment.PropertyMappings.Add(propertyMapping2);

            Assert.Equal(2, databaseMapping.GetComplexPropertyMappings(typeof(object)).Count());
        }
        public void GetEntityTypeMapping_should_return_mapping_for_type_by_clrType()
        {
            var databaseMapping = new DbDatabaseMapping()
                .Initialize(new EdmModel().Initialize(), new DbDatabaseMetadata());
            var entityType = new EdmEntityType { Name = "Foo" };
            entityType.SetClrType(typeof(object));
            var entityTypeMapping = new DbEntityTypeMapping { EntityType = entityType };
            entityTypeMapping.SetClrType(typeof(object));
            databaseMapping.AddEntitySetMapping(new EdmEntitySet()).EntityTypeMappings.Add(entityTypeMapping);

            Assert.Same(entityTypeMapping, databaseMapping.GetEntityTypeMapping(typeof(object)));
        }
        private void RemoveFragment(
            EdmEntitySet entitySet, DbEntityTypeMapping entityTypeMapping, DbEntityTypeMappingFragment fragment)
        {
            // Make the default discriminator nullable if this type isn't using it but there is a base type
            var defaultDiscriminator = fragment.GetDefaultDiscriminator();
            if (defaultDiscriminator != null
                && entityTypeMapping.EntityType.BaseType != null)
            {
                var columnMapping =
                    _tableMappings[fragment.Table].ColumnMappings.SingleOrDefault(
                        cm => cm.Column == defaultDiscriminator);
                if (columnMapping != null)
                {
                    var propertyMapping = columnMapping.PropertyMappings.SingleOrDefault(
                        pm => pm.EntityType == entityTypeMapping.EntityType);
                    if (propertyMapping != null)
                    {
                        columnMapping.PropertyMappings.Remove(propertyMapping);
                    }
                }
                defaultDiscriminator.IsNullable = true;
            }

            entityTypeMapping.TypeMappingFragments.Remove(fragment);
            if (!entityTypeMapping.TypeMappingFragments.Any())
            {
                _databaseMapping.GetEntitySetMapping(entitySet).EntityTypeMappings.Remove(entityTypeMapping);
            }
        }
        /// <summary>
        ///     Determines if the table and entity type need mapping, and if not, removes the existing entity type mapping
        /// </summary>
        private bool FindPropertyEntityTypeMapping(
            TableMapping tableMapping,
            EdmEntitySet entitySet,
            EdmEntityType entityType,
            bool requiresIsTypeOf,
            out DbEntityTypeMapping entityTypeMapping,
            out DbEntityTypeMappingFragment fragment)
        {
            entityTypeMapping = null;
            fragment = null;
            var mapping = (from etm in _databaseMapping.GetEntityTypeMappings(entityType)
                           from tmf in etm.TypeMappingFragments
                           where tmf.Table == tableMapping.Table
                           select new
                                      {
                                          TypeMapping = etm,
                                          Fragment = tmf
                                      }).SingleOrDefault();

            if (mapping != null)
            {
                entityTypeMapping = mapping.TypeMapping;
                fragment = mapping.Fragment;
                if (!requiresIsTypeOf
                    && entityType.IsAbstract)
                {
                    RemoveFragment(entitySet, mapping.TypeMapping, mapping.Fragment);
                    return false;
                }
                return true;
            }
            else
            {
                return false;
            }
        }
        private DbEntityTypeMapping FindConditionTypeMapping(
            EdmEntityType entityType, bool requiresSplit, DbEntityTypeMapping propertiesTypeMapping)
        {
            var conditionTypeMapping = propertiesTypeMapping;

            if (requiresSplit)
            {
                if (!entityType.IsAbstract)
                {
                    conditionTypeMapping = propertiesTypeMapping.Clone();
                    conditionTypeMapping.IsHierarchyMapping = false;

                    var parentEntitySetMapping =
                        _databaseMapping.GetEntitySetMappings().Single(
                            esm => esm.EntityTypeMappings.Contains(propertiesTypeMapping));
                    parentEntitySetMapping.EntityTypeMappings.Add(conditionTypeMapping);
                }
                propertiesTypeMapping.TypeMappingFragments.Each(tmf => tmf.ColumnConditions.Clear());
            }
            return conditionTypeMapping;
        }
 private static DbEntityTypeMappingFragment FindConditionTypeMappingFragment(
     TableMapping tableMapping, DbEntityTypeMappingFragment propertiesTypeMappingFragment,
     DbEntityTypeMapping conditionTypeMapping)
 {
     var conditionTypeMappingFragment =
         conditionTypeMapping.TypeMappingFragments.SingleOrDefault(x => x.Table == tableMapping.Table);
     if (conditionTypeMappingFragment == null)
     {
         conditionTypeMappingFragment = EntityMappingOperations.CreateTypeMappingFragment(
             conditionTypeMapping, propertiesTypeMappingFragment, tableMapping.Table);
         conditionTypeMappingFragment.SetIsConditionOnlyFragment(true);
         if (propertiesTypeMappingFragment.GetDefaultDiscriminator() != null)
         {
             conditionTypeMappingFragment.SetDefaultDiscriminator(
                 propertiesTypeMappingFragment.GetDefaultDiscriminator());
             propertiesTypeMappingFragment.RemoveDefaultDiscriminatorAnnotation();
         }
     }
     return conditionTypeMappingFragment;
 }
        public void Configure(
            DbDatabaseMapping databaseMapping,
            DbProviderManifest providerManifest,
            EdmEntityType entityType,
            ref DbEntityTypeMapping entityTypeMapping,
            bool isMappingAnyInheritedProperty,
            int configurationIndex,
            int configurationCount)
        {
            Contract.Requires(entityType != null);
            Contract.Requires(databaseMapping != null);
            Contract.Requires(providerManifest != null);

            var isIdentityTable = entityType.BaseType == null && configurationIndex == 0;

            var fragment = FindOrCreateTypeMappingFragment(
                databaseMapping, ref entityTypeMapping, configurationIndex, entityType, providerManifest);
            var fromTable = fragment.Table;
            bool isTableSharing;
            var toTable = FindOrCreateTargetTable(
                databaseMapping, fragment, entityType, fromTable, out isTableSharing);

            var isSharingTableWithBase = DiscoverIsSharingWithBase(databaseMapping, entityType, toTable);

            // Ensure all specified properties are the only ones present in this fragment and table
            var mappingsToContain = DiscoverAllMappingsToContain(
                databaseMapping, entityType, toTable, isSharingTableWithBase);

            // Validate that specified properties can be mapped
            var mappingsToMove = fragment.PropertyMappings.ToList();

            foreach (var propertyPath in mappingsToContain)
            {
                var propertyMapping = fragment.PropertyMappings.SingleOrDefault(
                    pm =>
                    pm.PropertyPath.SequenceEqual(propertyPath));

                if (propertyMapping == null)
                {
                    throw Error.EntityMappingConfiguration_DuplicateMappedProperty(
                        entityType.Name, propertyPath.ToString());
                }
                mappingsToMove.Remove(propertyMapping);
            }

            // Add table constraint if there are no inherited properties
            if (!isIdentityTable)
            {
                bool isSplitting;
                var parentTable = FindParentTable(
                    databaseMapping,
                    fromTable,
                    entityTypeMapping,
                    toTable,
                    isMappingAnyInheritedProperty,
                    configurationIndex,
                    configurationCount,
                    out isSplitting);
                if (parentTable != null)
                {
                    DatabaseOperations.AddTypeConstraint(entityType, parentTable, toTable, isSplitting);
                }
            }

            // Update AssociationSetMappings (IAs) and FKs
            if (fromTable != toTable)
            {
                if (Properties == null)
                {
                    AssociationMappingOperations.MoveAllDeclaredAssociationSetMappings(
                        databaseMapping, entityType, fromTable, toTable, !isTableSharing);
                    ForeignKeyPrimitiveOperations.MoveAllDeclaredForeignKeyConstraintsForPrimaryKeyColumns(
                        entityType, fromTable, toTable);
                }
                if (isMappingAnyInheritedProperty)
                {
                    // With TPC, we need to move down FK constraints, even on PKs (except type mapping constraints that are not about associations)
                    ForeignKeyPrimitiveOperations.CopyAllForeignKeyConstraintsForPrimaryKeyColumns(
                        databaseMapping.Database, fromTable, toTable);
                }
            }

            if (mappingsToMove.Any())
            {
                DbTableMetadata extraTable = null;
                if (configurationIndex < configurationCount - 1)
                {
                    // Move all extra properties to a single new fragment
                    var anyPropertyMapping = mappingsToMove.First();
                    extraTable = FindTableForTemporaryExtraPropertyMapping(
                        databaseMapping, entityType, fromTable, toTable, anyPropertyMapping);
                    var extraFragment = EntityMappingOperations.CreateTypeMappingFragment(
                        entityTypeMapping, fragment, extraTable);
                    var requiresUpdate = extraTable != fromTable;

                    foreach (var pm in mappingsToMove)
                    {
                        // move the property mapping from toFragment to extraFragment
                        EntityMappingOperations.MovePropertyMapping(
                            databaseMapping.Database, fragment, extraFragment, pm, requiresUpdate, true);
                    }
                }
                else
                {
                    // Move each extra property mapping to a fragment refering to the table with the base mapping
                    DbTableMetadata unmappedTable = null;
                    foreach (var pm in mappingsToMove)
                    {
                        extraTable = FindTableForExtraPropertyMapping(
                            databaseMapping, entityType, fromTable, toTable, ref unmappedTable, pm);

                        var extraFragment =
                            entityTypeMapping.TypeMappingFragments.SingleOrDefault(tmf => tmf.Table == extraTable);

                        if (extraFragment == null)
                        {
                            extraFragment = EntityMappingOperations.CreateTypeMappingFragment(
                                entityTypeMapping, fragment, extraTable);
                            extraFragment.SetIsUnmappedPropertiesFragment(true);
                        }

                        if (extraTable == fromTable)
                        {
                            // move the default discriminator along with the properties
                            MoveDefaultDiscriminator(fragment, extraFragment);
                        }

                        var requiresUpdate = extraTable != fromTable;
                        EntityMappingOperations.MovePropertyMapping(
                            databaseMapping.Database, fragment, extraFragment, pm, requiresUpdate, true);
                    }
                }
            }

            // Ensure all property mappings refer to the table in the fragment
            // Uniquify: true if table sharing, false otherwise
            //           FK names should be uniquified
            //           declared properties are moved, inherited ones are copied (duplicated)
            EntityMappingOperations.UpdatePropertyMappings(
                databaseMapping.Database, fromTable, fragment, !isTableSharing);

            // Configure Conditions for the fragment
            ConfigureDefaultDiscriminator(entityType, fragment, isSharingTableWithBase);
            ConfigureConditions(databaseMapping, entityType, fragment, providerManifest);

            // Ensure all conditions refer to columns on the table in the fragment
            EntityMappingOperations.UpdateConditions(databaseMapping.Database, fromTable, fragment);

            ForeignKeyPrimitiveOperations.UpdatePrincipalTables(
                databaseMapping, entityType, fromTable, toTable, isMappingAnyInheritedProperty);

            CleanupUnmappedArtifacts(databaseMapping, fromTable);
            CleanupUnmappedArtifacts(databaseMapping, toTable);

            toTable.SetConfiguration(this);
        }
        private void WriteEntityTypeMappingElement(DbEntityTypeMapping entityTypeMapping)
        {
            _xmlWriter.WriteStartElement(MslConstants.Element_EntityTypeMapping);
            _xmlWriter.WriteAttributeString(
                MslConstants.Attribute_TypeName,
                GetEntityTypeName(
                    _entityTypeNamespace + "." + entityTypeMapping.EntityType.Name, entityTypeMapping.IsHierarchyMapping));

            foreach (var mappingFragment in entityTypeMapping.TypeMappingFragments)
            {
                WriteMappingFragmentElement(mappingFragment);
            }

            _xmlWriter.WriteEndElement();
        }
        private static DbTableMetadata FindParentTable(
            DbDatabaseMapping databaseMapping,
            DbTableMetadata fromTable,
            DbEntityTypeMapping entityTypeMapping,
            DbTableMetadata toTable,
            bool isMappingInheritedProperties,
            int configurationIndex,
            int configurationCount,
            out bool isSplitting)
        {
            DbTableMetadata parentTable = null;
            isSplitting = false;
            // Check for entity splitting first, since splitting on a derived type in TPT/TPC will always have fromTable != toTable
            if (entityTypeMapping.UsesOtherTables(toTable)
                || configurationCount > 1)
            {
                if (configurationIndex != 0)
                {
                    // Entity Splitting case
                    parentTable = entityTypeMapping.GetPrimaryTable();
                    isSplitting = true;
                }
            }

            if (parentTable == null && fromTable != toTable
                && !isMappingInheritedProperties)
            {
                // TPT case
                var baseType = entityTypeMapping.EntityType.BaseType;
                while (baseType != null
                       && parentTable == null)
                {
                    // Traverse to first anscestor with a mapping
                    var baseMapping = databaseMapping.GetEntityTypeMappings(baseType).FirstOrDefault();
                    if (baseMapping != null)
                    {
                        parentTable = baseMapping.GetPrimaryTable();
                    }
                    baseType = baseType.BaseType;
                }
            }

            return parentTable;
        }
        public void GetEntityTypeMapping_should_return_mapping_for_type()
        {
            var databaseMapping = new DbDatabaseMapping()
                .Initialize(new EdmModel().Initialize(), new DbDatabaseMetadata());
            var entityType = new EdmEntityType();
            var entityTypeMapping = new DbEntityTypeMapping { EntityType = entityType };
            databaseMapping.AddEntitySetMapping(new EdmEntitySet()).EntityTypeMappings.Add(entityTypeMapping);

            Assert.Same(entityTypeMapping, databaseMapping.GetEntityTypeMapping(entityType));
        }
        public static DbEntityTypeMappingFragment CreateTypeMappingFragment(
            DbEntityTypeMapping entityTypeMapping, DbEntityTypeMappingFragment templateFragment, DbTableMetadata table)
        {
            var fragment = new DbEntityTypeMappingFragment
                {
                    Table = table
                };
            entityTypeMapping.TypeMappingFragments.Add(fragment);

            // Move all PK mappings to the extra fragment
            foreach (
                var pkPropertyMapping in templateFragment.PropertyMappings.Where(pm => pm.Column.IsPrimaryKeyColumn))
            {
                CopyPropertyMappingToFragment(pkPropertyMapping, fragment, true);
            }
            return fragment;
        }
        private DbEntityTypeMappingFragment FindOrCreateTypeMappingFragment(
            DbDatabaseMapping databaseMapping,
            ref DbEntityTypeMapping entityTypeMapping,
            int configurationIndex,
            EdmEntityType entityType,
            DbProviderManifest providerManifest)
        {
            DbEntityTypeMappingFragment fragment = null;

            if (entityTypeMapping == null)
            {
                Contract.Assert(entityType.IsAbstract);
                new EntityTypeMappingGenerator(providerManifest).
                    Generate(entityType, databaseMapping);
                entityTypeMapping = databaseMapping.GetEntityTypeMapping(entityType);
                configurationIndex = 0;
            }

            if (configurationIndex < entityTypeMapping.TypeMappingFragments.Count)
            {
                fragment = entityTypeMapping.TypeMappingFragments[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.TypeMappingFragments[0].Table;
                fragment = EntityMappingOperations.CreateTypeMappingFragment(
                    entityTypeMapping,
                    entityTypeMapping.TypeMappingFragments[0],
                    databaseMapping.Database.AddTable(templateTable.Name, templateTable));
            }
            return fragment;
        }
 private static DbEntityTypeMappingFragment GetFragmentForPropertyMapping(
     DbEntityTypeMapping entityTypeMapping, EdmProperty property)
 {
     return entityTypeMapping.TypeMappingFragments
         .SingleOrDefault(tmf => tmf.PropertyMappings.Any(pm => pm.PropertyPath.Last() == property));
 }
        internal void ConfigureTablesAndConditions(
            DbEntityTypeMapping entityTypeMapping,
            DbDatabaseMapping databaseMapping,
            DbProviderManifest providerManifest)
        {
            Contract.Requires(databaseMapping != null);
            Contract.Requires(providerManifest != null);

            var entityType
                = (entityTypeMapping != null)
                      ? entityTypeMapping.EntityType
                      : databaseMapping.Model.GetEntityType(ClrType);

            if (_entityMappingConfigurations.Any())
            {
                for (var i = 0; i < _entityMappingConfigurations.Count; i++)
                {
                    _entityMappingConfigurations[i]
                        .Configure(
                            databaseMapping,
                            providerManifest,
                            entityType,
                            ref entityTypeMapping,
                            IsMappingAnyInheritedProperty(entityType),
                            i,
                            _entityMappingConfigurations.Count);
                }
            }
            else
            {
                ConfigureUnconfiguredType(databaseMapping, providerManifest, entityType);
            }
        }