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())); }