public void Creates_foreign_key_using_given_dependent_and_principal_properties() { DependentType.GetOrAddProperty("SomeNavID", typeof(int), shadowProperty: true); DependentType.GetOrAddProperty("SomeNavPeEKaY", typeof(int), shadowProperty: true); DependentType.GetOrAddProperty("PrincipalEntityID", typeof(int), shadowProperty: true); DependentType.GetOrAddProperty("PrincipalEntityPeEKaY", typeof(int), shadowProperty: true); var fkProperty1 = DependentType.GetOrAddProperty("ThatsNotTrue!", typeof(int), shadowProperty: true); var fkProperty2 = DependentType.GetOrAddProperty("ThatsImpossible!", typeof(int), shadowProperty: true); var principalKeyProperty1 = PrincipalType.GetOrAddProperty("SearchYourFeelings", typeof(int), shadowProperty: true); var principalKeyProperty2 = PrincipalType.GetOrAddProperty("YouKnowItToBeTrue!", typeof(int), shadowProperty: true); var fk = new ForeignKeyConvention().FindOrCreateForeignKey( PrincipalType, DependentType, "SomeNav", "SomeInverse", new[] { fkProperty1, fkProperty2 }, new[] { principalKeyProperty1, principalKeyProperty2 }, isUnqiue: false); Assert.Same(fkProperty1, fk.Properties[0]); Assert.Same(fkProperty2, fk.Properties[1]); Assert.Same(principalKeyProperty1, fk.ReferencedProperties[0]); Assert.Same(principalKeyProperty2, fk.ReferencedProperties[1]); Assert.False(fk.IsUnique); Assert.True(fk.IsRequired); }
public void Creates_foreign_key_using_given_properties() { DependentType.GetOrAddProperty("SomeNavID", typeof(int), shadowProperty: true); DependentType.GetOrAddProperty("SomeNavPeEKaY", typeof(int), shadowProperty: true); DependentType.GetOrAddProperty("PrincipalEntityID", typeof(int), shadowProperty: true); DependentType.GetOrAddProperty("PrincipalEntityPeEKaY", typeof(int), shadowProperty: true); var fkProperty1 = DependentType.GetOrAddProperty("ThatsNotTrue!", typeof(int), shadowProperty: true); var fkProperty2 = DependentType.GetOrAddProperty("ThatsImpossible!", typeof(int?), shadowProperty: true); var fk = new ForeignKeyConvention().FindOrCreateForeignKey( PrincipalType, DependentType, "SomeNav", "SomeInverse", new[] { fkProperty1, fkProperty2 }, new Property[0], isUnqiue: false); Assert.Same(fkProperty1, fk.Properties[0]); Assert.Same(fkProperty2, fk.Properties[1]); Assert.Equal(2, fk.ReferencedProperties.Count); Assert.Equal("ThatsNotTrue!Key", fk.ReferencedProperties[0].Name); Assert.Same(typeof(int), fk.ReferencedProperties[0].PropertyType); Assert.True(fk.ReferencedProperties[0].IsShadowProperty); Assert.Equal("ThatsImpossible!Key", fk.ReferencedProperties[1].Name); Assert.Same(typeof(int), fk.ReferencedProperties[1].PropertyType); Assert.True(fk.ReferencedProperties[1].IsShadowProperty); Assert.False(fk.IsUnique); Assert.True(fk.IsRequired); }
public void Creates_unique_foreign_key_using_dependent_PK_if_no_matching_FK_property_found() { var fk = new ForeignKeyConvention().FindOrCreateForeignKey(PrincipalType, DependentType, "SomeNav", "SomeInverse", isUnqiue: true); Assert.Same(DependentType.GetPrimaryKey().Properties.Single(), fk.Properties.Single()); Assert.Same(PrimaryKey, fk.ReferencedProperties.Single()); Assert.True(fk.IsUnique); Assert.True(fk.IsRequired); }
public void Creates_foreign_key_matching_principal_type_name_plus_PK_name() { var fkProperty = DependentType.GetOrAddProperty("PrincipalEntityPeEKaY", typeof(int), shadowProperty: true); var fk = new ForeignKeyConvention().FindOrCreateForeignKey(PrincipalType, DependentType, "SomeNav", "SomeInverse", isUnqiue: false); Assert.Same(fkProperty, fk.Properties.Single()); Assert.Same(PrimaryKey, fk.ReferencedProperties.Single()); Assert.False(fk.IsUnique); Assert.True(fk.IsRequired); }
public void Creates_foreign_key_based_on_type_name_if_no_appropriate_property_is_found() { var fk = new ForeignKeyConvention().FindOrCreateForeignKey(PrincipalType, DependentType, null, null, isUnqiue: false); Assert.Equal("PrincipalEntityId", fk.Properties.Single().Name); Assert.Equal(typeof(int), fk.Properties.Single().PropertyType); Assert.True(fk.Properties.Single().IsShadowProperty); Assert.False(fk.Properties.Single().IsConcurrencyToken); Assert.Same(PrimaryKey, fk.ReferencedProperties.Single()); Assert.False(fk.IsUnique); Assert.True(fk.IsRequired); }
public void Creates_correct_foreign_key_for_entity_with_composite_key() { var fk = new ForeignKeyConvention().FindOrCreateForeignKey( _model.GetEntityType(typeof(PrincipalEntityWithCompositeKey)), _model.GetEntityType(typeof(DependentEntityWithCompositeKey)), "NavProp", "NavProp", isUnqiue: false); Assert.Equal(2, fk.ReferencedProperties.Count); Assert.Equal(typeof(int), fk.ReferencedProperties[0].PropertyType); Assert.Equal(typeof(string), fk.ReferencedProperties[1].PropertyType); }
public void Does_not_match_existing_FK_if_FK_already_has_different_uniqueness() { var fkProperty = DependentType.GetOrAddProperty("SharedFk", typeof(int), shadowProperty: true); var fk = DependentType.GetOrAddForeignKey(PrincipalType.GetPrimaryKey(), fkProperty); fk.IsUnique = true; var newFk = new ForeignKeyConvention().FindOrCreateForeignKey( PrincipalType, DependentType, "SomeNav", "SomeInverse", new[] { fkProperty }, new Property[0], isUnqiue: false); Assert.NotSame(fk, newFk); Assert.Same(fkProperty, newFk.Properties.Single()); Assert.Same(PrimaryKey, newFk.ReferencedProperties.Single()); Assert.False(newFk.IsUnique); Assert.True(newFk.IsRequired); }
public void Creates_foreign_key_using_given_property() { DependentType.GetOrAddProperty("SomeNavID", typeof(int), shadowProperty: true); DependentType.GetOrAddProperty("SomeNavPeEKaY", typeof(int), shadowProperty: true); DependentType.GetOrAddProperty("PrincipalEntityID", typeof(int), shadowProperty: true); DependentType.GetOrAddProperty("PrincipalEntityPeEKaY", typeof(int), shadowProperty: true); var fkProperty = DependentType.GetOrAddProperty("No!No!", typeof(int), shadowProperty: true); var fk = new ForeignKeyConvention().FindOrCreateForeignKey( PrincipalType, DependentType, "SomeNav", "SomeInverse", new[] { fkProperty }, new Property[0], isUnqiue: false); Assert.Same(fkProperty, fk.Properties.Single()); Assert.Same(PrimaryKey, fk.ReferencedProperties.Single()); Assert.False(fk.IsUnique); Assert.True(fk.IsRequired); }
public RelationshipBuilder ForeignKey(IList <PropertyInfo> propertyAccessList) { var dependentProperties = propertyAccessList .Select(pi => _dependentType.TryGetProperty(pi.Name) ?? _dependentType.AddProperty(pi)) .ToArray(); var foreignKey = Metadata; if (!foreignKey.Properties.SequenceEqual(dependentProperties)) { foreignKey = new ForeignKeyConvention().FindOrCreateForeignKey( _principalType, _dependentType, _navigationToPrincipal != null ? _navigationToPrincipal.Name : null, _navigationToDependent != null ? _navigationToDependent.Name : null, new[] { dependentProperties }, Metadata.IsUnique); // TODO: Remove FK only if it was added by convention Metadata.EntityType.RemoveForeignKey(Metadata); // TODO: Remove property only if it was added by convention foreach (var property in Metadata.Properties.Except(dependentProperties)) { // TODO: This check not needed once only removing properties added by convention var dependentPk = Metadata.EntityType.TryGetKey(); if (dependentPk == null || !dependentPk.Properties.Contains(property)) { Metadata.EntityType.RemoveProperty(property); } } if (_navigationToPrincipal != null) { _navigationToPrincipal.ForeignKey = foreignKey; } if (_navigationToDependent != null) { _navigationToDependent.ForeignKey = foreignKey; } } return(new RelationshipBuilder( foreignKey, ModelBuilder, _principalType, _dependentType, _navigationToPrincipal, _navigationToDependent)); }
private InternalRelationshipBuilder ReplaceForeignKey( [NotNull] EntityType principalType, [NotNull] EntityType dependentType, [CanBeNull] IReadOnlyList <Property> foreignKeyProperties, [CanBeNull] IReadOnlyList <Property> referencedProperties, [CanBeNull] string navigationToPrincipalName, [CanBeNull] string navigationToDependentName, bool oneToOne, ConfigurationSource configurationSource) { var entityTypeBuilder = ModelBuilder.Entity(Metadata.EntityType.Name, configurationSource); if (!entityTypeBuilder.RemoveRelationship(Metadata, configurationSource)) { return(null); } var dependentEntityTypeBuilder = ModelBuilder.Entity(dependentType.Name, configurationSource); var foreignKey = foreignKeyProperties == null ? null : new ForeignKeyConvention().TryGetForeignKey( principalType, dependentType, null, null, foreignKeyProperties, referencedProperties, oneToOne); var existingForeignKey = foreignKey != null; if (!existingForeignKey) { if (foreignKeyProperties != null) { foreignKey = dependentType.TryGetForeignKey(foreignKeyProperties); if (foreignKey != null && !dependentEntityTypeBuilder.RemoveRelationship(foreignKey, configurationSource)) { return(null); } } foreignKey = new ForeignKeyConvention().CreateForeignKeyByConvention( principalType, dependentType, navigationToPrincipalName, foreignKeyProperties, referencedProperties, oneToOne); if (foreignKey == null) { if (configurationSource == ConfigurationSource.Explicit && foreignKeyProperties != null && foreignKeyProperties.Any()) { if (referencedProperties == null || !referencedProperties.Any()) { referencedProperties = principalType.GetPrimaryKey().Properties; } if (referencedProperties.Count != foreignKeyProperties.Count) { throw new InvalidOperationException( Strings.ForeignKeyCountMismatch( Property.Format(foreignKeyProperties), foreignKeyProperties[0].EntityType.Name, Property.Format(referencedProperties), principalType.Name)); } if (!referencedProperties.Select(p => p.UnderlyingType).SequenceEqual(foreignKeyProperties.Select(p => p.UnderlyingType))) { throw new InvalidOperationException( Strings.ForeignKeyTypeMismatch( Property.Format(foreignKeyProperties), foreignKeyProperties[0].EntityType.Name, principalType.Name)); } } return(null); } } var navigationToPrincipalSet = dependentEntityTypeBuilder .Navigation(navigationToPrincipalName, foreignKey, pointsToPrincipal: true, configurationSource: configurationSource); Debug.Assert(navigationToPrincipalSet); var principalEntityTypeBuilder = ModelBuilder.Entity(foreignKey.ReferencedEntityType.Name, configurationSource); var navigationToDependentSet = principalEntityTypeBuilder .Navigation(navigationToDependentName, foreignKey, pointsToPrincipal: false, configurationSource: configurationSource); Debug.Assert(navigationToDependentSet); var builder = entityTypeBuilder.Relationship(foreignKey, existingForeignKey, configurationSource); Debug.Assert(builder != null); builder.MergeConfigurationSourceWith(this); return(builder); }
public virtual InternalRelationshipBuilder Relationship( [NotNull] InternalEntityBuilder principalEntityTypeBuilder, [NotNull] InternalEntityBuilder dependentEntityTypeBuilder, [CanBeNull] string navigationToPrincipalName, [CanBeNull] string navigationToDependentName, ConfigurationSource configurationSource, bool?oneToOne = null, bool strictPrincipal = true) { Check.NotNull(principalEntityTypeBuilder, "principalEntityTypeBuilder"); Check.NotNull(dependentEntityTypeBuilder, "dependentEntityTypeBuilder"); if (dependentEntityTypeBuilder != this) { return(dependentEntityTypeBuilder.Relationship( principalEntityTypeBuilder, dependentEntityTypeBuilder, navigationToPrincipalName, navigationToDependentName, configurationSource, oneToOne, strictPrincipal)); } if (!string.IsNullOrEmpty(navigationToPrincipalName) && !dependentEntityTypeBuilder.CanAdd(navigationToPrincipalName, isNavigation: true, configurationSource: configurationSource)) { return(null); } if (!string.IsNullOrEmpty(navigationToDependentName) && !principalEntityTypeBuilder.CanAdd(navigationToDependentName, isNavigation: true, configurationSource: configurationSource)) { return(null); } var principalEntityType = principalEntityTypeBuilder.Metadata; var dependentEntityType = dependentEntityTypeBuilder.Metadata; if (principalEntityType.TryGetPrimaryKey() == null) { if (configurationSource == ConfigurationSource.Explicit) { throw new InvalidOperationException(Strings.PrincipalEntityTypeRequiresKey(principalEntityType.Name)); } return(null); } var navigationToPrincipal = string.IsNullOrEmpty(navigationToPrincipalName) ? null : dependentEntityType.TryGetNavigation(navigationToPrincipalName); if (navigationToPrincipal != null && navigationToPrincipal.IsCompatible(principalEntityType, dependentEntityType, strictPrincipal ? (bool?)true : null, oneToOne)) { return(Relationship(navigationToPrincipal, configurationSource, navigationToDependentName)); } var navigationToDependent = string.IsNullOrEmpty(navigationToDependentName) ? null : principalEntityType.TryGetNavigation(navigationToDependentName); if (navigationToDependent != null && navigationToDependent.IsCompatible(principalEntityType, dependentEntityType, strictPrincipal? (bool?)false : null, oneToOne)) { return(Relationship(navigationToDependent, configurationSource, navigationToPrincipalName)); } if (!RemoveRelationships(configurationSource, navigationToPrincipal?.ForeignKey, navigationToDependent?.ForeignKey)) { return(null); } navigationToPrincipalName = navigationToPrincipalName == "" ? null : navigationToPrincipalName; navigationToDependentName = navigationToDependentName == "" ? null : navigationToDependentName; var foreignKey = new ForeignKeyConvention() .CreateForeignKeyByConvention( principalEntityType, dependentEntityType, navigationToPrincipalName, null, null, oneToOne); if (foreignKey == null) { return(null); } var relationshipBuilder = new InternalRelationshipBuilder(foreignKey, dependentEntityTypeBuilder.ModelBuilder, foreignKeyConfigurationSource: null); Debug.Assert(relationshipBuilder.Metadata.EntityType == Metadata); _relationshipBuilders.Value.Add(foreignKey, relationshipBuilder, configurationSource); if (navigationToPrincipalName != null) { var navigationToPrincipalSet = dependentEntityTypeBuilder .Navigation(navigationToPrincipalName, foreignKey, pointsToPrincipal: true, configurationSource: configurationSource); Debug.Assert(navigationToPrincipalSet); } if (navigationToDependentName != null) { var navigationToDependentSet = principalEntityTypeBuilder .Navigation(navigationToDependentName, foreignKey, pointsToPrincipal: false, configurationSource: configurationSource); Debug.Assert(navigationToDependentSet); } return(relationshipBuilder); }
public virtual InternalRelationshipBuilder ReplaceForeignKey( [NotNull] InternalRelationshipBuilder relationshipBuilder, [NotNull] IReadOnlyList <Property> dependentProperties, [NotNull] IReadOnlyList <Property> principalProperties, ConfigurationSource configurationSource) { if (!_relationshipBuilders.Value.Remove(relationshipBuilder.Metadata, configurationSource)) { return(null); } // TODO: avoid removing and readding the navigation property if (relationshipBuilder.NavigationToPrincipal != null) { relationshipBuilder.DependentType.RemoveNavigation(relationshipBuilder.NavigationToPrincipal); } if (relationshipBuilder.NavigationToDependent != null) { relationshipBuilder.PrincipalType.RemoveNavigation(relationshipBuilder.NavigationToDependent); } var entityType = relationshipBuilder.Metadata.EntityType; // TODO: Remove FK only if it was added by convention // Issue #213 entityType.RemoveForeignKey(relationshipBuilder.Metadata); var newForeignKey = new ForeignKeyConvention().FindOrCreateForeignKey( relationshipBuilder.PrincipalType, relationshipBuilder.DependentType, relationshipBuilder.NavigationToPrincipal != null ? relationshipBuilder.NavigationToPrincipal.Name : null, relationshipBuilder.NavigationToDependent != null ? relationshipBuilder.NavigationToDependent.Name : null, dependentProperties, principalProperties, ((IForeignKey)relationshipBuilder.Metadata).IsUnique); // TODO: Remove principal key only if it was added by convention // Issue #213 var currentPrincipalKey = relationshipBuilder.Metadata.ReferencedKey; if (currentPrincipalKey != newForeignKey.ReferencedKey && currentPrincipalKey != currentPrincipalKey.EntityType.TryGetPrimaryKey() && currentPrincipalKey.Properties.All(p => p.IsShadowProperty)) { currentPrincipalKey.EntityType.RemoveKey(currentPrincipalKey); } var propertiesInUse = entityType.Keys.SelectMany(k => k.Properties) .Concat(entityType.ForeignKeys.SelectMany(k => k.Properties)) .Concat(relationshipBuilder.Metadata.ReferencedEntityType.Keys.SelectMany(k => k.Properties)) .Concat(relationshipBuilder.Metadata.ReferencedEntityType.ForeignKeys.SelectMany(k => k.Properties)) .Concat(dependentProperties) .Concat(principalProperties) .Where(p => p.IsShadowProperty) .Distinct(); var propertiesToRemove = Metadata.Properties .Concat(relationshipBuilder.Metadata.ReferencedKey.Properties) .Where(p => p.IsShadowProperty) .Distinct() .Except(propertiesInUse) .ToList(); // TODO: Remove property only if it was added by convention // Issue #213 foreach (var property in propertiesToRemove) { property.EntityType.RemoveProperty(property); } var navigationToPrincipal = relationshipBuilder.NavigationToPrincipal; if (navigationToPrincipal != null) { navigationToPrincipal = relationshipBuilder.DependentType.AddNavigation( navigationToPrincipal.Name, newForeignKey, navigationToPrincipal.PointsToPrincipal); } var navigationToDependent = relationshipBuilder.NavigationToDependent; if (navigationToDependent != null) { navigationToDependent = relationshipBuilder.PrincipalType.AddNavigation( navigationToDependent.Name, newForeignKey, navigationToDependent.PointsToPrincipal); } var owner = this; if (Metadata != newForeignKey.EntityType) { owner = ModelBuilder.Entity(newForeignKey.EntityType.Name, configurationSource); } var builder = owner._relationshipBuilders.Value.TryGetValue(newForeignKey, configurationSource); if (builder != null) { if (builder.PrincipalType == relationshipBuilder.PrincipalType && builder.DependentType == relationshipBuilder.DependentType && builder.NavigationToPrincipal == navigationToPrincipal && builder.NavigationToDependent == navigationToDependent) { return(builder); } if (!owner._relationshipBuilders.Value.Remove(newForeignKey, configurationSource)) { return(null); } } builder = new InternalRelationshipBuilder( relationshipBuilder, newForeignKey, navigationToPrincipal, navigationToDependent); owner._relationshipBuilders.Value.Add(newForeignKey, builder, configurationSource); return(builder); }
private InternalRelationshipBuilder ReplaceForeignKey() { var newForeignKey = new ForeignKeyConvention().FindOrCreateForeignKey( _principalType, _dependentType, _navigationToPrincipal != null ? _navigationToPrincipal.Name : null, _navigationToDependent != null ? _navigationToDependent.Name : null, _dependentProperties, _principalProperties, Metadata.IsUnique); if (_navigationToPrincipal != null) { _dependentType.RemoveNavigation(_navigationToPrincipal); } if (_navigationToDependent != null) { _principalType.RemoveNavigation(_navigationToDependent); } var entityType = Metadata.EntityType; // TODO: Remove FK only if it was added by convention entityType.RemoveForeignKey(Metadata); // TODO: Remove principal key only if it was added by convention var currentPrincipalKey = Metadata.ReferencedKey; if (currentPrincipalKey != newForeignKey.ReferencedKey && currentPrincipalKey != currentPrincipalKey.EntityType.TryGetPrimaryKey() && currentPrincipalKey.Properties.All(p => p.IsShadowProperty)) { currentPrincipalKey.EntityType.RemoveKey(currentPrincipalKey); } var propertiesInUse = entityType.Keys.SelectMany(k => k.Properties) .Concat(entityType.ForeignKeys.SelectMany(k => k.Properties)) .Concat(Metadata.ReferencedEntityType.Keys.SelectMany(k => k.Properties)) .Concat(Metadata.ReferencedEntityType.ForeignKeys.SelectMany(k => k.Properties)) .Concat(_principalProperties) .Concat(_dependentProperties) .Where(p => p.IsShadowProperty) .Distinct(); var propertiesToRemove = Metadata.Properties .Concat(Metadata.ReferencedKey.Properties) .Where(p => p.IsShadowProperty) .Distinct() .Except(propertiesInUse); // TODO: Remove property only if it was added by convention foreach (var property in propertiesToRemove) { property.EntityType.RemoveProperty(property); } if (_navigationToPrincipal != null) { _navigationToPrincipal.ForeignKey = newForeignKey; _dependentType.AddNavigation(_navigationToPrincipal); } if (_navigationToDependent != null) { _navigationToDependent.ForeignKey = newForeignKey; _principalType.AddNavigation(_navigationToDependent); } return(new InternalRelationshipBuilder(newForeignKey, this)); }