public void Property_DeclaringEntityType_Returns_DeclaredType()
        {
            Mock<EntityTypeConfiguration> mockDeclaringType = new Mock<EntityTypeConfiguration>();
            NavigationPropertyConfiguration navigationProperty = new NavigationPropertyConfiguration(new MockPropertyInfo(), EdmMultiplicity.One, mockDeclaringType.Object);

            Assert.Equal(mockDeclaringType.Object, navigationProperty.DeclaringEntityType);
        }
        public void Required_ModifiesMultiplicityToOne()
        {
            NavigationPropertyConfiguration navigationProperty = new NavigationPropertyConfiguration(new MockPropertyInfo(), EdmMultiplicity.ZeroOrOne, new EntityTypeConfiguration());

            navigationProperty.Required();

            Assert.Equal(EdmMultiplicity.One, navigationProperty.Multiplicity);
        }
        public void Optional_Throws_IfMultiplicityIsMany()
        {
            NavigationPropertyConfiguration navigationProperty =
                new NavigationPropertyConfiguration(new MockPropertyInfo(typeof(int[]), "P"), EdmMultiplicity.Many, new EntityTypeConfiguration());

            Assert.Throws<InvalidOperationException>(
                () => navigationProperty.Optional(),
                "Cannot change multiplicity of the collection navigation property 'P'.");
        }
        public void HasConstraint_ThrowsArgumentNull_ForNullPrincipalProperty()
        {
            // Arrange
            Mock <EntityTypeConfiguration>  mockDeclaringType  = new Mock <EntityTypeConfiguration>();
            NavigationPropertyConfiguration navigationProperty =
                new NavigationPropertyConfiguration(new MockPropertyInfo(), EdmMultiplicity.One,
                                                    mockDeclaringType.Object);

            // Act & Assert
            Assert.ThrowsArgumentNull(() => navigationProperty.HasConstraint(new MockPropertyInfo(),
                                                                             principalPropertyInfo: null),
                                      "principalPropertyInfo");
        }
        public void CascadeOnDelete_ModifiesOnDelete_WithParameter()
        {
            // Arrange
            NavigationPropertyConfiguration navigationProperty =
                new NavigationPropertyConfiguration(new MockPropertyInfo(), EdmMultiplicity.ZeroOrOne,
                                                    new EntityTypeConfiguration());

            // Act
            navigationProperty.CascadeOnDelete(cascade: false);

            // Assert
            Assert.Equal(EdmOnDeleteAction.None, navigationProperty.OnDeleteAction);
        }
        public void HasNavigationPropertyLink(NavigationPropertyConfiguration navigationProperty, Func <EntityInstanceContext <TEntityType>, IEdmNavigationProperty, Uri> navigationLinkFactory, bool followsConventions)
        {
            if (navigationProperty == null)
            {
                throw Error.ArgumentNull("navigationProperty");
            }

            if (navigationLinkFactory == null)
            {
                throw Error.ArgumentNull("navigationLinkFactory");
            }

            _configuration.HasNavigationPropertyLink(navigationProperty, new NavigationLinkBuilder((entity, property) => navigationLinkFactory(UpCastEntityInstanceContext(entity), property), followsConventions));
        }
        public void HasConstraint_Throws_NotSupported_ForMany()
        {
            // Arrange
            ODataModelBuilder               builder            = new ODataModelBuilder();
            EntityTypeConfiguration         entityType         = builder.AddEntity(typeof(Dependent));
            NavigationPropertyConfiguration navigationProperty =
                new NavigationPropertyConfiguration(new MockPropertyInfo(typeof(IList <int>), "Users"),
                                                    EdmMultiplicity.Many, entityType);

            // Assert & Act
            Assert.Throws <NotSupportedException>(
                () => navigationProperty.HasConstraint(new MockPropertyInfo(), new MockPropertyInfo()),
                String.Format(SRResources.ReferentialConstraintOnManyNavigationPropertyNotSupported,
                              navigationProperty.Name, navigationProperty.DeclaringEntityType.ClrType.FullName));
        }
        public IEntitySetConfiguration HasNavigationPropertyLink(NavigationPropertyConfiguration navigationProperty, Func<EntityInstanceContext, IEdmNavigationProperty, Uri> navigationLinkFactory)
        {
            if (navigationProperty == null)
            {
                throw Error.ArgumentNull("navigationProperty");
            }

            if (navigationLinkFactory == null)
            {
                throw Error.ArgumentNull("navigationLinkFactory");
            }

            _navigationPropertyLinkBuilders.Add(navigationProperty.Name, navigationLinkFactory);
            return this;
        }
        public IEntitySetConfiguration HasNavigationPropertyLink(NavigationPropertyConfiguration navigationProperty, Func <EntityInstanceContext, IEdmNavigationProperty, Uri> navigationLinkFactory)
        {
            if (navigationProperty == null)
            {
                throw Error.ArgumentNull("navigationProperty");
            }

            if (navigationLinkFactory == null)
            {
                throw Error.ArgumentNull("navigationLinkFactory");
            }

            _navigationPropertyLinkBuilders.Add(navigationProperty.Name, navigationLinkFactory);
            return(this);
        }
Exemple #10
0
        public NavigationPropertyConfiguration HasRequired <TTargetEntity>(
            Expression <Func <TEntityType, TTargetEntity> > navigationPropertyExpression,
            Expression <Func <TEntityType, TTargetEntity, bool> > referentialConstraintExpression) where TTargetEntity : class
        {
            NavigationPropertyConfiguration navigation = GetOrCreateNavigationProperty(navigationPropertyExpression,
                                                                                       EdmMultiplicity.One);

            IDictionary <PropertyInfo, PropertyInfo> referentialConstraints =
                PropertyPairSelectorVisitor.GetSelectedProperty(referentialConstraintExpression);

            foreach (KeyValuePair <PropertyInfo, PropertyInfo> constraint in referentialConstraints)
            {
                navigation.HasConstraint(constraint);
            }

            return(navigation);
        }
Exemple #11
0
        public void HasRequired_CanSetMultipleForeignKeyProperties_ForReferencialConstraint()
        {
            // Arrange
            ODataModelBuilder builder = new ODataModelBuilder();

            // Act
            NavigationPropertyConfiguration navigationProperty =
                builder.Entity <MultiRole>()
                .HasRequired(r => r.User, (r, u) => r.UserKey1 == u.UserId1 && r.UserKey2 == u.UserId2);

            // Assert
            Assert.Equal(2, navigationProperty.DependentProperties.Count());
            Assert.Same(typeof(MultiRole).GetProperty("UserKey1"), navigationProperty.DependentProperties.First());
            Assert.Same(typeof(MultiRole).GetProperty("UserKey2"), navigationProperty.DependentProperties.Last());

            Assert.Equal(2, navigationProperty.PrincipalProperties.Count());
            Assert.Same(typeof(MultiUser).GetProperty("UserId1"), navigationProperty.PrincipalProperties.First());
            Assert.Same(typeof(MultiUser).GetProperty("UserId2"), navigationProperty.PrincipalProperties.Last());
        }
        public void HasConstraint_Throws_ReferentialConstraintPropertyTypeNotValid()
        {
            // Arrange
            PropertyInfo principalPropertyInfo = typeof(Principal).GetProperty("MockPrincipal");
            PropertyInfo dependentPropertyInfo = typeof(Dependent).GetProperty("MockDependent");

            ODataModelBuilder builder = new ODataModelBuilder();

            builder.AddEntity(typeof(Principal));
            EntityTypeConfiguration         dependentEntity    = builder.AddEntity(typeof(Dependent));
            NavigationPropertyConfiguration navigationProperty =
                new NavigationPropertyConfiguration(typeof(Dependent).GetProperty("Principal"), EdmMultiplicity.One,
                                                    dependentEntity);

            // Act & Assert
            Assert.Throws <InvalidOperationException>(
                () => navigationProperty.HasConstraint(dependentPropertyInfo, principalPropertyInfo),
                String.Format(SRResources.ReferentialConstraintPropertyTypeNotValid, "System.Web.Http.OData.MockType"));
        }
        public void HasConstraint_Throws_DependentAndPrincipalTypeNotMatch()
        {
            // Arrange
            PropertyInfo principalPropertyInfo = typeof(Principal).GetProperty("PrincipalKey2");
            PropertyInfo dependentPropertyInfo = typeof(Dependent).GetProperty("DependentKey1");

            ODataModelBuilder builder = new ODataModelBuilder();

            builder.AddEntity(typeof(Principal));
            EntityTypeConfiguration         dependentEntity    = builder.AddEntity(typeof(Dependent));
            NavigationPropertyConfiguration navigationProperty =
                new NavigationPropertyConfiguration(typeof(Dependent).GetProperty("Principal"), EdmMultiplicity.One,
                                                    dependentEntity);

            // Act & Assert
            Assert.Throws <InvalidOperationException>(
                () => navigationProperty.HasConstraint(dependentPropertyInfo, principalPropertyInfo),
                String.Format(SRResources.DependentAndPrincipalTypeNotMatch, "System.Int32", "System.String"));
        }
Exemple #14
0
        private IEnumerable <IEdmStructuralProperty> ReorderDependentProperties(
            NavigationPropertyConfiguration navProperty)
        {
            EntityTypeConfiguration principalEntity = _configurations.OfType <EntityTypeConfiguration>()
                                                      .FirstOrDefault(e => e.ClrType == navProperty.RelatedClrType);

            Contract.Assert(principalEntity != null);

            int keyCount = principalEntity.Keys().Count();

            if (keyCount != navProperty.PrincipalProperties.Count())
            {
                throw Error.InvalidOperation(SRResources.DependentPropertiesNotMatchWithPrincipalKeys,
                                             String.Join(",", navProperty.DependentProperties.Select(e => e.PropertyType.FullName)),
                                             String.Join(",", principalEntity.Keys.Select(e => e.PropertyInfo.PropertyType.FullName)));
            }

            // OData V3 spec says:
            // The property references for the principal entity MUST be the same property references specified
            // in the edm:Key of the principal entity type.
            IList <IEdmStructuralProperty> dependentProperties = new List <IEdmStructuralProperty>();

            foreach (PropertyConfiguration key in principalEntity.Keys())
            {
                PropertyInfo dependent =
                    navProperty.ReferentialConstraint.FirstOrDefault(r => r.Value.PropertyType == key.PropertyInfo.PropertyType &&
                                                                     r.Value.Name == key.PropertyInfo.Name).Key;

                if (dependent != null)
                {
                    dependentProperties.Add(_properties[dependent] as IEdmStructuralProperty);
                }
            }

            if (keyCount != dependentProperties.Count)
            {
                throw Error.InvalidOperation(SRResources.DependentPropertiesNotMatchWithPrincipalKeys,
                                             String.Join(",", navProperty.DependentProperties.Select(e => e.PropertyType.FullName)),
                                             String.Join(",", principalEntity.Keys.Select(e => e.PropertyInfo.PropertyType.FullName)));
            }

            return(dependentProperties);
        }
        public NavigationPropertyBinding AddBinding(NavigationPropertyConfiguration navigationConfiguration, IEntitySetConfiguration targetEntitySet)
        {
            NavigationPropertyBinding navigationPropertyBinding = null;

            if (_entitySetBindings.ContainsKey(navigationConfiguration))
            {
                navigationPropertyBinding = _entitySetBindings[navigationConfiguration];
                if (navigationPropertyBinding.EntitySet != targetEntitySet)
                {
                    throw Error.NotSupported(SRResources.RebindingNotSupported);
                }
            }
            else
            {
                navigationPropertyBinding = new NavigationPropertyBinding(navigationConfiguration, targetEntitySet);
                _entitySetBindings[navigationConfiguration] = navigationPropertyBinding;
            }
            return(navigationPropertyBinding);
        }
        /// <summary>
        /// Adds a new EDM navigation property to this entity type.
        /// </summary>
        /// <param name="navigationProperty">The backing CLR property.</param>
        /// <param name="multiplicity">The <see cref="EdmMultiplicity"/> of the navigation property.</param>
        /// <returns>Returns the <see cref="NavigationPropertyConfiguration"/> of the added property.</returns>
        public NavigationPropertyConfiguration AddNavigationProperty(PropertyInfo navigationProperty, EdmMultiplicity multiplicity)
        {
            if (navigationProperty == null)
            {
                throw Error.ArgumentNull("navigationProperty");
            }

            if (!navigationProperty.ReflectedType.IsAssignableFrom(ClrType))
            {
                throw Error.InvalidOperation(SRResources.PropertyDoesNotBelongToType, navigationProperty.Name, ClrType.FullName);
            }

            ValidatePropertyNotAlreadyDefinedInBaseTypes(navigationProperty);
            ValidatePropertyNotAlreadyDefinedInDerivedTypes(navigationProperty);

            PropertyConfiguration           propertyConfig;
            NavigationPropertyConfiguration navigationPropertyConfig;

            if (ExplicitProperties.ContainsKey(navigationProperty))
            {
                propertyConfig = ExplicitProperties[navigationProperty];
                if (propertyConfig.Kind != PropertyKind.Navigation)
                {
                    throw Error.Argument("navigationProperty", SRResources.MustBeNavigationProperty, navigationProperty.Name, ClrType.FullName);
                }

                navigationPropertyConfig = propertyConfig as NavigationPropertyConfiguration;
                if (navigationPropertyConfig.Multiplicity != multiplicity)
                {
                    throw Error.Argument("navigationProperty", SRResources.MustHaveMatchingMultiplicity, navigationProperty.Name, multiplicity);
                }
            }
            else
            {
                navigationPropertyConfig = new NavigationPropertyConfiguration(navigationProperty, multiplicity);
                ExplicitProperties[navigationProperty] = navigationPropertyConfig;
                // make sure the related type is configured
                ModelBuilder.AddEntity(navigationPropertyConfig.RelatedClrType);
            }
            return(navigationPropertyConfig);
        }
        public IEntitySetConfiguration HasNavigationPropertyLink(NavigationPropertyConfiguration navigationProperty, Func <EntityInstanceContext, IEdmNavigationProperty, Uri> navigationLinkFactory)
        {
            if (navigationProperty == null)
            {
                throw Error.ArgumentNull("navigationProperty");
            }

            if (navigationLinkFactory == null)
            {
                throw Error.ArgumentNull("navigationLinkFactory");
            }

            IEntityTypeConfiguration declaringEntityType = navigationProperty.DeclaringEntityType;

            if (!(declaringEntityType.IsAssignableFrom(EntityType) || EntityType.IsAssignableFrom(declaringEntityType)))
            {
                throw Error.InvalidOperation(SRResources.NavigationPropertyNotInHierarchy, declaringEntityType.FullName, EntityType.FullName, Name);
            }

            _navigationPropertyLinkBuilders.Add(navigationProperty, navigationLinkFactory);
            return(this);
        }
        /// <summary>
        /// Configures the navigation link for the given navigation property for entities from this entity set.
        /// </summary>
        /// <param name="navigationProperty">The navigation property for which the navigation link is being generated.</param>
        /// <param name="navigationLinkBuilder">The builder used to generate the navigation link.</param>
        /// <returns>Returns itself so that multiple calls can be chained.</returns>
        public virtual EntitySetConfiguration HasNavigationPropertyLink(NavigationPropertyConfiguration navigationProperty, NavigationLinkBuilder navigationLinkBuilder)
        {
            if (navigationProperty == null)
            {
                throw Error.ArgumentNull("navigationProperty");
            }

            if (navigationLinkBuilder == null)
            {
                throw Error.ArgumentNull("navigationLinkBuilder");
            }

            EntityTypeConfiguration declaringEntityType = navigationProperty.DeclaringEntityType;

            if (!(declaringEntityType.IsAssignableFrom(EntityType) || EntityType.IsAssignableFrom(declaringEntityType)))
            {
                throw Error.Argument("navigationProperty", SRResources.NavigationPropertyNotInHierarchy, declaringEntityType.FullName, EntityType.FullName, Name);
            }

            _navigationPropertyLinkBuilders[navigationProperty] = navigationLinkBuilder;
            return(this);
        }
        /// <summary>
        /// Finds the binding for the given navigation property.
        /// </summary>
        /// <param name="autoCreate">Tells whether the binding should be auto created if it does not exist.</param>
        /// <param name="navigationConfiguration">The navigation property.</param>
        /// <returns>The <see cref="NavigationPropertyBindingConfiguration"/> so that it can be further configured.</returns>
        public virtual NavigationPropertyBindingConfiguration FindBinding(NavigationPropertyConfiguration navigationConfiguration, bool autoCreate)
        {
            if (navigationConfiguration == null)
            {
                throw Error.ArgumentNull("navigationConfiguration");
            }

            if (_entitySetBindings.ContainsKey(navigationConfiguration))
            {
                return(_entitySetBindings[navigationConfiguration]);
            }

            if (!autoCreate)
            {
                return(null);
            }

            Type entityType = navigationConfiguration.RelatedClrType;

            EntitySetConfiguration[] matchingSets = _modelBuilder.EntitySets.Where(es => es.EntityType.ClrType == entityType).ToArray();
            if (matchingSets.Count() == 1)
            {
                return(AddBinding(navigationConfiguration, matchingSets[0]));
            }
            else if (!matchingSets.Any())
            {
                return(null);
            }
            else
            {
                throw Error.NotSupported(
                          SRResources.CannotAutoCreateMultipleCandidates,
                          navigationConfiguration.Name,
                          navigationConfiguration.DeclaringEntityType.FullName,
                          Name,
                          String.Join(", ", matchingSets.Select(entitySet => entitySet.Name)));
            }
        }
        public NavigationPropertyConfiguration AddNavigationProperty(PropertyInfo navigationProperty, EdmMultiplicity multiplicity)
        {
            if (navigationProperty == null)
            {
                throw Error.ArgumentNull("navigationProperty");
            }

            if (navigationProperty.DeclaringType != ClrType)
            {
                throw Error.Argument("navigationProperty", SRResources.PropertyDoesNotBelongToType);
            }

            PropertyConfiguration           propertyConfig;
            NavigationPropertyConfiguration navigationPropertyConfig;

            if (ExplicitProperties.ContainsKey(navigationProperty))
            {
                propertyConfig = ExplicitProperties[navigationProperty];
                if (propertyConfig.Kind != PropertyKind.Navigation)
                {
                    throw Error.Argument("navigationProperty", SRResources.MustBeNavigationProperty, navigationProperty.Name);
                }

                navigationPropertyConfig = propertyConfig as NavigationPropertyConfiguration;
                if (navigationPropertyConfig.Multiplicity != multiplicity)
                {
                    throw Error.Argument("navigationProperty", SRResources.MustHaveMatchingMultiplicity, navigationProperty.Name, multiplicity);
                }
            }
            else
            {
                navigationPropertyConfig = new NavigationPropertyConfiguration(navigationProperty, multiplicity);
                ExplicitProperties[navigationProperty] = navigationPropertyConfig;
                // make sure the related type is configured
                ModelBuilder.AddEntity(navigationPropertyConfig.RelatedClrType);
            }
            return(navigationPropertyConfig);
        }
        public void HasConstraint_Throws_ReferentialConstraintAlreadyConfigured_Principal()
        {
            // Arrange
            PropertyInfo principalPropertyInfo      = typeof(Principal).GetProperty("PrincipalKey1");
            PropertyInfo dependentPropertyInfo      = typeof(Dependent).GetProperty("DependentKey1");
            PropertyInfo otherPrincipalPropertyInfo = typeof(Dependent).GetProperty("DependentKey2");

            ODataModelBuilder builder = new ODataModelBuilder();

            builder.AddEntity(typeof(Principal));
            EntityTypeConfiguration         dependentEntity    = builder.AddEntity(typeof(Dependent));
            NavigationPropertyConfiguration navigationProperty =
                new NavigationPropertyConfiguration(typeof(Dependent).GetProperty("Principal"), EdmMultiplicity.One,
                                                    dependentEntity);

            navigationProperty.HasConstraint(dependentPropertyInfo, principalPropertyInfo);

            // Act & Assert
            Assert.Throws <InvalidOperationException>(
                () => navigationProperty.HasConstraint(otherPrincipalPropertyInfo, principalPropertyInfo),
                String.Format(SRResources.ReferentialConstraintAlreadyConfigured,
                              "principal", "PrincipalKey1", "dependent", "DependentKey1"));
        }
        public void HasConstraint_Works_SetupReferentialConstraint()
        {
            // Arrange
            ODataModelBuilder               builder            = new ODataModelBuilder();
            EntityTypeConfiguration         entity             = builder.AddEntity(typeof(Dependent));
            NavigationPropertyConfiguration navigationProperty =
                new NavigationPropertyConfiguration(typeof(Dependent).GetProperty("Principal"),
                                                    EdmMultiplicity.ZeroOrOne, entity);

            PropertyInfo principalProperty = typeof(Principal).GetProperty("PrincipalKey1");
            PropertyInfo dependentProperty = typeof(Dependent).GetProperty("DependentKey1");

            // Act
            navigationProperty.HasConstraint(dependentProperty, principalProperty);

            // Assert
            PropertyInfo actualDependentInfo = Assert.Single(navigationProperty.DependentProperties);

            Assert.Same(dependentProperty, actualDependentInfo);

            PropertyInfo actualPrincipalInfo = Assert.Single(navigationProperty.PrincipalProperties);

            Assert.Same(principalProperty, actualPrincipalInfo);
        }
        /// <summary>
        /// Binds the given navigation property to the target entity set.
        /// </summary>
        /// <param name="navigationConfiguration">The navigation property.</param>
        /// <param name="targetEntitySet">The target entity set.</param>
        /// <returns>The <see cref="NavigationPropertyBindingConfiguration"/> so that it can be further configured.</returns>
        public virtual NavigationPropertyBindingConfiguration AddBinding(NavigationPropertyConfiguration navigationConfiguration, EntitySetConfiguration targetEntitySet)
        {
            if (navigationConfiguration == null)
            {
                throw Error.ArgumentNull("navigationConfiguration");
            }

            if (targetEntitySet == null)
            {
                throw Error.ArgumentNull("targetEntitySet");
            }

            EntityTypeConfiguration declaringEntityType = navigationConfiguration.DeclaringEntityType;

            if (!(declaringEntityType.IsAssignableFrom(EntityType) || EntityType.IsAssignableFrom(declaringEntityType)))
            {
                throw Error.Argument("navigationConfiguration", SRResources.NavigationPropertyNotInHierarchy, declaringEntityType.FullName, EntityType.FullName, Name);
            }

            NavigationPropertyBindingConfiguration navigationPropertyBinding = null;

            if (_entitySetBindings.ContainsKey(navigationConfiguration))
            {
                navigationPropertyBinding = _entitySetBindings[navigationConfiguration];
                if (navigationPropertyBinding.EntitySet != targetEntitySet)
                {
                    throw Error.NotSupported(SRResources.RebindingNotSupported);
                }
            }
            else
            {
                navigationPropertyBinding = new NavigationPropertyBindingConfiguration(navigationConfiguration, targetEntitySet);
                _entitySetBindings[navigationConfiguration] = navigationPropertyBinding;
            }
            return(navigationPropertyBinding);
        }
        public void HasConstraint_Throws_DependentAndPrincipalTypeNotMatch()
        {
            // Arrange
            PropertyInfo principalPropertyInfo = typeof(Principal).GetProperty("PrincipalKey2");
            PropertyInfo dependentPropertyInfo = typeof(Dependent).GetProperty("DependentKey1");

            ODataModelBuilder builder = new ODataModelBuilder();
            builder.AddEntity(typeof(Principal));
            EntityTypeConfiguration dependentEntity = builder.AddEntity(typeof(Dependent));
            NavigationPropertyConfiguration navigationProperty =
                new NavigationPropertyConfiguration(typeof(Dependent).GetProperty("Principal"), EdmMultiplicity.One,
                    dependentEntity);

            // Act & Assert
            Assert.Throws<InvalidOperationException>(
                () => navigationProperty.HasConstraint(dependentPropertyInfo, principalPropertyInfo),
                String.Format(SRResources.DependentAndPrincipalTypeNotMatch, "System.Int32", "System.String"));
        }
Exemple #25
0
 public NavigationPropertyBinding(NavigationPropertyConfiguration navigationProperty, EntitySetConfiguration entitySet)
 {
     NavigationProperty = navigationProperty;
     EntitySet          = entitySet;
     _linkFactory       = null;
 }
        public void Ctor_MultiplicityProperty_IsInitializedProperly()
        {
            NavigationPropertyConfiguration navigationProperty = new NavigationPropertyConfiguration(new MockPropertyInfo(), EdmMultiplicity.ZeroOrOne, new EntityTypeConfiguration());

            Assert.Equal(EdmMultiplicity.ZeroOrOne, navigationProperty.Multiplicity);
        }
        /// <summary>
        /// Adds a new EDM navigation property to this entity type.
        /// </summary>
        /// <param name="navigationProperty">The backing CLR property.</param>
        /// <param name="multiplicity">The <see cref="EdmMultiplicity"/> of the navigation property.</param>
        /// <returns>Returns the <see cref="NavigationPropertyConfiguration"/> of the added property.</returns>
        public virtual NavigationPropertyConfiguration AddNavigationProperty(PropertyInfo navigationProperty, EdmMultiplicity multiplicity)
        {
            if (navigationProperty == null)
            {
                throw Error.ArgumentNull("navigationProperty");
            }

            if (!navigationProperty.ReflectedType.IsAssignableFrom(ClrType))
            {
                throw Error.Argument("navigationProperty", SRResources.PropertyDoesNotBelongToType, navigationProperty.Name, ClrType.FullName);
            }

            ValidatePropertyNotAlreadyDefinedInBaseTypes(navigationProperty);
            ValidatePropertyNotAlreadyDefinedInDerivedTypes(navigationProperty);

            PropertyConfiguration propertyConfig;
            NavigationPropertyConfiguration navigationPropertyConfig;

            if (ExplicitProperties.ContainsKey(navigationProperty))
            {
                propertyConfig = ExplicitProperties[navigationProperty];
                if (propertyConfig.Kind != PropertyKind.Navigation)
                {
                    throw Error.Argument("navigationProperty", SRResources.MustBeNavigationProperty, navigationProperty.Name, ClrType.FullName);
                }

                navigationPropertyConfig = propertyConfig as NavigationPropertyConfiguration;
                if (navigationPropertyConfig.Multiplicity != multiplicity)
                {
                    throw Error.Argument("navigationProperty", SRResources.MustHaveMatchingMultiplicity, navigationProperty.Name, multiplicity);
                }
            }
            else
            {
                navigationPropertyConfig = new NavigationPropertyConfiguration(navigationProperty, multiplicity, this);
                ExplicitProperties[navigationProperty] = navigationPropertyConfig;
                // make sure the related type is configured
                ModelBuilder.AddEntity(navigationPropertyConfig.RelatedClrType);
            }
            return navigationPropertyConfig;
        }
        public void HasConstraint_DoesnotAddTwice_ForSameConstraint()
        {
            // Arrange
            ODataModelBuilder builder = new ODataModelBuilder();
            EntityTypeConfiguration entity = builder.AddEntity(typeof(Dependent));
            NavigationPropertyConfiguration navigationProperty =
                new NavigationPropertyConfiguration(typeof(Dependent).GetProperty("Principal"),
                    EdmMultiplicity.ZeroOrOne, entity);

            PropertyInfo principalProperty = typeof(Principal).GetProperty("PrincipalKey1");
            PropertyInfo dependentProperty = typeof(Dependent).GetProperty("DependentKey1");

            // Act
            navigationProperty.HasConstraint(dependentProperty, principalProperty);
            navigationProperty.HasConstraint(dependentProperty, principalProperty);

            // Assert
            PropertyInfo actualInfo = Assert.Single(navigationProperty.DependentProperties);
            Assert.Same(dependentProperty, actualInfo);

            PropertyInfo actualPrincipalInfo = Assert.Single(navigationProperty.PrincipalProperties);
            Assert.Same(principalProperty, actualPrincipalInfo);
        }
 /// <summary>
 /// Finds the <see cref="NavigationPropertyBindingConfiguration"/> for the given navigation property.
 /// </summary>
 /// <param name="navigationConfiguration">The navigation property.</param>
 /// <param name="autoCreate">Represents a value specifying if the binding should be created if it is not found.</param>
 /// <returns>The binding if found.</returns>
 public NavigationPropertyBindingConfiguration FindBinding(NavigationPropertyConfiguration navigationConfiguration, bool autoCreate)
 {
     return(_configuration.FindBinding(navigationConfiguration, autoCreate));
 }
 /// <summary>
 /// Finds the binding for the given navigation property and tries to create it if it doesnot exist.
 /// </summary>
 /// <param name="navigationConfiguration">The navigation property.</param>
 /// <returns>The <see cref="NavigationPropertyBindingConfiguration"/> so that it can be further configured.</returns>
 public virtual NavigationPropertyBindingConfiguration FindBinding(NavigationPropertyConfiguration navigationConfiguration)
 {
     return FindBinding(navigationConfiguration, autoCreate: true);
 }
 /// <summary>
 /// Removes the binding for the given navigation property.
 /// </summary>
 /// <param name="navigationConfiguration">The navigation property</param>
 public virtual void RemoveBinding(NavigationPropertyConfiguration navigationConfiguration)
 {
     if (_entitySetBindings.ContainsKey(navigationConfiguration))
     {
         _entitySetBindings.Remove(navigationConfiguration);
     }
 }
        /// <summary>
        /// Binds the given navigation property to the target entity set.
        /// </summary>
        /// <param name="navigationConfiguration">The navigation property.</param>
        /// <param name="targetEntitySet">The target entity set.</param>
        /// <returns>The <see cref="NavigationPropertyBindingConfiguration"/> so that it can be further configured.</returns>
        public virtual NavigationPropertyBindingConfiguration AddBinding(NavigationPropertyConfiguration navigationConfiguration, EntitySetConfiguration targetEntitySet)
        {
            if (navigationConfiguration == null)
            {
                throw Error.ArgumentNull("navigationConfiguration");
            }

            if (targetEntitySet == null)
            {
                throw Error.ArgumentNull("targetEntitySet");
            }

            EntityTypeConfiguration declaringEntityType = navigationConfiguration.DeclaringEntityType;
            if (!(declaringEntityType.IsAssignableFrom(EntityType) || EntityType.IsAssignableFrom(declaringEntityType)))
            {
                throw Error.Argument("navigationConfiguration", SRResources.NavigationPropertyNotInHierarchy, declaringEntityType.FullName, EntityType.FullName, Name);
            }

            NavigationPropertyBindingConfiguration navigationPropertyBinding = null;
            if (_entitySetBindings.ContainsKey(navigationConfiguration))
            {
                navigationPropertyBinding = _entitySetBindings[navigationConfiguration];
                if (navigationPropertyBinding.EntitySet != targetEntitySet)
                {
                    throw Error.NotSupported(SRResources.RebindingNotSupported);
                }
            }
            else
            {
                navigationPropertyBinding = new NavigationPropertyBindingConfiguration(navigationConfiguration, targetEntitySet);
                _entitySetBindings[navigationConfiguration] = navigationPropertyBinding;
            }
            return navigationPropertyBinding;
        }
        /// <summary>
        /// Configures the navigation link for the given navigation property for entities from this entity set.
        /// </summary>
        /// <param name="navigationProperty">The navigation property for which the navigation link is being generated.</param>
        /// <param name="navigationLinkBuilder">The builder used to generate the navigation link.</param>
        /// <returns>Returns itself so that multiple calls can be chained.</returns>
        public virtual EntitySetConfiguration HasNavigationPropertyLink(NavigationPropertyConfiguration navigationProperty, NavigationLinkBuilder navigationLinkBuilder)
        {
            if (navigationProperty == null)
            {
                throw Error.ArgumentNull("navigationProperty");
            }

            if (navigationLinkBuilder == null)
            {
                throw Error.ArgumentNull("navigationLinkBuilder");
            }

            EntityTypeConfiguration declaringEntityType = navigationProperty.DeclaringEntityType;
            if (!(declaringEntityType.IsAssignableFrom(EntityType) || EntityType.IsAssignableFrom(declaringEntityType)))
            {
                throw Error.Argument("navigationProperty", SRResources.NavigationPropertyNotInHierarchy, declaringEntityType.FullName, EntityType.FullName, Name);
            }

            _navigationPropertyLinkBuilders[navigationProperty] = navigationLinkBuilder;
            return this;
        }
        private IEnumerable<IEdmStructuralProperty> ReorderDependentProperties(
            NavigationPropertyConfiguration navProperty)
        {
            EntityTypeConfiguration principalEntity = _configurations.OfType<EntityTypeConfiguration>()
                .FirstOrDefault(e => e.ClrType == navProperty.RelatedClrType);
            Contract.Assert(principalEntity != null);

            int keyCount = principalEntity.Keys().Count();
            if (keyCount != navProperty.PrincipalProperties.Count())
            {
                throw Error.InvalidOperation(SRResources.DependentPropertiesNotMatchWithPrincipalKeys,
                    String.Join(",", navProperty.DependentProperties.Select(e => e.PropertyType.FullName)),
                    String.Join(",", principalEntity.Keys.Select(e => e.PropertyInfo.PropertyType.FullName)));
            }

            // OData V3 spec says:
            // The property references for the principal entity MUST be the same property references specified
            // in the edm:Key of the principal entity type.
            IList<IEdmStructuralProperty> dependentProperties = new List<IEdmStructuralProperty>();
            foreach (PropertyConfiguration key in principalEntity.Keys())
            {
                PropertyInfo dependent =
                    navProperty.ReferentialConstraint.FirstOrDefault(r => r.Value.PropertyType == key.PropertyInfo.PropertyType &&
                        r.Value.Name == key.PropertyInfo.Name).Key;

                if (dependent != null)
                {
                    dependentProperties.Add(_properties[dependent] as IEdmStructuralProperty);
                }
            }

            if (keyCount != dependentProperties.Count)
            {
                throw Error.InvalidOperation(SRResources.DependentPropertiesNotMatchWithPrincipalKeys,
                    String.Join(",", navProperty.DependentProperties.Select(e => e.PropertyType.FullName)),
                    String.Join(",", principalEntity.Keys.Select(e => e.PropertyInfo.PropertyType.FullName)));
            }

            return dependentProperties;
        }
 public NavigationPropertyBinding AddBinding(NavigationPropertyConfiguration navigationConfiguration, IEntitySetConfiguration targetEntitySet)
 {
     NavigationPropertyBinding navigationPropertyBinding = null;
     if (_entitySetBindings.ContainsKey(navigationConfiguration))
     {
         navigationPropertyBinding = _entitySetBindings[navigationConfiguration];
         if (navigationPropertyBinding.EntitySet != targetEntitySet)
         {
             throw Error.NotSupported(SRResources.RebindingNotSupported);
         }
     }
     else
     {
         navigationPropertyBinding = new NavigationPropertyBinding(navigationConfiguration, targetEntitySet);
         _entitySetBindings[navigationConfiguration] = navigationPropertyBinding;
     }
     return navigationPropertyBinding;
 }
        public void HasConstraint_Throws_ReferentialConstraintPropertyTypeNotValid()
        {
            // Arrange
            PropertyInfo principalPropertyInfo = typeof(Principal).GetProperty("MockPrincipal");
            PropertyInfo dependentPropertyInfo = typeof(Dependent).GetProperty("MockDependent");

            ODataModelBuilder builder = new ODataModelBuilder();
            builder.AddEntity(typeof(Principal));
            EntityTypeConfiguration dependentEntity = builder.AddEntity(typeof(Dependent));
            NavigationPropertyConfiguration navigationProperty =
                new NavigationPropertyConfiguration(typeof(Dependent).GetProperty("Principal"), EdmMultiplicity.One,
                    dependentEntity);

            // Act & Assert
            Assert.Throws<InvalidOperationException>(
                () => navigationProperty.HasConstraint(dependentPropertyInfo, principalPropertyInfo),
                String.Format(SRResources.ReferentialConstraintPropertyTypeNotValid, "System.Web.Http.OData.MockType"));
        }
        public void Ctor_MultiplicityProperty_IsInitializedProperly()
        {
            NavigationPropertyConfiguration navigationProperty = new NavigationPropertyConfiguration(new MockPropertyInfo(), EdmMultiplicity.ZeroOrOne, new EntityTypeConfiguration());

            Assert.Equal(EdmMultiplicity.ZeroOrOne, navigationProperty.Multiplicity);
        }
        /// <summary>
        /// Configures the navigation link for the given navigation property for entities from this entity set.
        /// </summary>
        /// <param name="navigationProperty">The navigation property for which the navigation link is being generated.</param>
        /// <param name="navigationLinkFactory">The builder used to generate the navigation link.</param>
        /// <returns>Returns itself so that multiple calls can be chained.</returns>
        public virtual EntitySetConfiguration HasNavigationPropertyLink(NavigationPropertyConfiguration navigationProperty, Func<EntityInstanceContext, IEdmNavigationProperty, Uri> navigationLinkFactory)
        {
            if (navigationProperty == null)
            {
                throw Error.ArgumentNull("navigationProperty");
            }

            if (navigationLinkFactory == null)
            {
                throw Error.ArgumentNull("navigationLinkFactory");
            }

            EntityTypeConfiguration declaringEntityType = navigationProperty.DeclaringEntityType;
            if (!(declaringEntityType.IsAssignableFrom(EntityType) || EntityType.IsAssignableFrom(declaringEntityType)))
            {
                throw Error.InvalidOperation(SRResources.NavigationPropertyNotInHierarchy, declaringEntityType.FullName, EntityType.FullName, Name);
            }

            _navigationPropertyLinkBuilders.Add(navigationProperty, navigationLinkFactory);
            return this;
        }
        /// <summary>
        /// Finds the binding for the given navigation property.
        /// </summary>
        /// <param name="autoCreate">Tells whether the binding should be auto created if it does not exist.</param>
        /// <param name="navigationConfiguration">The navigation property.</param>
        /// <returns>The <see cref="NavigationPropertyBindingConfiguration"/> so that it can be further configured.</returns>
        public virtual NavigationPropertyBindingConfiguration FindBinding(NavigationPropertyConfiguration navigationConfiguration, bool autoCreate)
        {
            if (navigationConfiguration == null)
            {
                throw Error.ArgumentNull("navigationConfiguration");
            }

            if (_entitySetBindings.ContainsKey(navigationConfiguration))
            {
                return _entitySetBindings[navigationConfiguration];
            }

            if (!autoCreate)
            {
                return null;
            }

            Type entityType = navigationConfiguration.RelatedClrType;
            EntitySetConfiguration[] matchingSets = _modelBuilder.EntitySets.Where(es => es.EntityType.ClrType == entityType).ToArray();
            if (matchingSets.Count() == 1)
            {
                return AddBinding(navigationConfiguration, matchingSets[0]);
            }
            else if (!matchingSets.Any())
            {
                return null;
            }
            else
            {
                throw Error.NotSupported(
                    SRResources.CannotAutoCreateMultipleCandidates,
                    navigationConfiguration.Name,
                    navigationConfiguration.DeclaringEntityType.FullName,
                    Name,
                    String.Join(", ", matchingSets.Select(entitySet => entitySet.Name)));
            }
        }
        public void HasConstraint_Throws_ReferentialConstraintAlreadyConfigured_Principal()
        {
            // Arrange
            PropertyInfo principalPropertyInfo = typeof(Principal).GetProperty("PrincipalKey1");
            PropertyInfo dependentPropertyInfo = typeof(Dependent).GetProperty("DependentKey1");
            PropertyInfo otherPrincipalPropertyInfo = typeof(Dependent).GetProperty("DependentKey2");

            ODataModelBuilder builder = new ODataModelBuilder();
            builder.AddEntity(typeof(Principal));
            EntityTypeConfiguration dependentEntity = builder.AddEntity(typeof(Dependent));
            NavigationPropertyConfiguration navigationProperty =
                new NavigationPropertyConfiguration(typeof(Dependent).GetProperty("Principal"), EdmMultiplicity.One,
                    dependentEntity);

            navigationProperty.HasConstraint(dependentPropertyInfo, principalPropertyInfo);

            // Act & Assert
            Assert.Throws<InvalidOperationException>(
                () => navigationProperty.HasConstraint(otherPrincipalPropertyInfo, principalPropertyInfo),
                String.Format(SRResources.ReferentialConstraintAlreadyConfigured,
                "principal", "PrincipalKey1", "dependent", "DependentKey1"));
        }
        public void HasConstraint_Throws_NotSupported_ForMany()
        {
            // Arrange
            ODataModelBuilder builder = new ODataModelBuilder();
            EntityTypeConfiguration entityType = builder.AddEntity(typeof(Dependent));
            NavigationPropertyConfiguration navigationProperty =
                new NavigationPropertyConfiguration(new MockPropertyInfo(typeof(IList<int>), "Users"),
                    EdmMultiplicity.Many, entityType);

            // Assert & Act
            Assert.Throws<NotSupportedException>(
                () => navigationProperty.HasConstraint(new MockPropertyInfo(), new MockPropertyInfo()),
                String.Format(SRResources.ReferentialConstraintOnManyNavigationPropertyNotSupported,
                    navigationProperty.Name, navigationProperty.DeclaringEntityType.ClrType.FullName));
        }
 /// <summary>
 /// Finds the binding for the given navigation property and tries to create it if it doesnot exist.
 /// </summary>
 /// <param name="navigationConfiguration">The navigation property.</param>
 /// <returns>The <see cref="NavigationPropertyBindingConfiguration"/> so that it can be further configured.</returns>
 public virtual NavigationPropertyBindingConfiguration FindBinding(NavigationPropertyConfiguration navigationConfiguration)
 {
     return(FindBinding(navigationConfiguration, autoCreate: true));
 }
 public NavigationPropertyBinding FindBinding(NavigationPropertyConfiguration navigationConfiguration)
 {
     return(_configuration.FindBinding(navigationConfiguration, autoCreate: true));
 }
        public void HasConstraint_ThrowsArgumentNull_ForNullPrincipalProperty()
        {
            // Arrange
            Mock<EntityTypeConfiguration> mockDeclaringType = new Mock<EntityTypeConfiguration>();
            NavigationPropertyConfiguration navigationProperty =
                new NavigationPropertyConfiguration(new MockPropertyInfo(), EdmMultiplicity.One,
                    mockDeclaringType.Object);

            // Act & Assert
            Assert.ThrowsArgumentNull(() => navigationProperty.HasConstraint(new MockPropertyInfo(),
                    principalPropertyInfo: null),
                "principalPropertyInfo");
        }
        /// <summary>
        /// Gets the builder used to generate navigation link for the given navigation property for entries from this entity set.
        /// </summary>
        /// <param name="navigationProperty">The navigation property.</param>
        /// <returns>The link builder.</returns>
        public virtual Func<EntityInstanceContext, IEdmNavigationProperty, Uri> GetNavigationPropertyLink(NavigationPropertyConfiguration navigationProperty)
        {
            if (navigationProperty == null)
            {
                throw Error.ArgumentNull("navigationProperty");
            }

            Func<EntityInstanceContext, IEdmNavigationProperty, Uri> navigationPropertyLinkBuilder;
            _navigationPropertyLinkBuilders.TryGetValue(navigationProperty, out navigationPropertyLinkBuilder);
            return navigationPropertyLinkBuilder;
        }
 public NavigationPropertyBinding(NavigationPropertyConfiguration navigationProperty, EntitySetConfiguration entitySet) 
 {
     NavigationProperty = navigationProperty;
     EntitySet = entitySet;
     _linkFactory = null;
 }
        public Func <EntityInstanceContext, IEdmNavigationProperty, Uri> GetNavigationPropertyLink(NavigationPropertyConfiguration navigationProperty)
        {
            if (navigationProperty == null)
            {
                throw Error.ArgumentNull("navigationProperty");
            }

            Func <EntityInstanceContext, IEdmNavigationProperty, Uri> navigationPropertyLinkBuilder;

            _navigationPropertyLinkBuilders.TryGetValue(navigationProperty, out navigationPropertyLinkBuilder);
            return(navigationPropertyLinkBuilder);
        }
        /// <summary>
        /// Gets the builder used to generate navigation link for the given navigation property for entries from this entity set.
        /// </summary>
        /// <param name="navigationProperty">The navigation property.</param>
        /// <returns>The link builder.</returns>
        public virtual NavigationLinkBuilder GetNavigationPropertyLink(NavigationPropertyConfiguration navigationProperty)
        {
            if (navigationProperty == null)
            {
                throw Error.ArgumentNull("navigationProperty");
            }

            NavigationLinkBuilder navigationPropertyLinkBuilder;
            _navigationPropertyLinkBuilders.TryGetValue(navigationProperty, out navigationPropertyLinkBuilder);
            return navigationPropertyLinkBuilder;
        }
        public void OnDeleteAction_Returns_NoneByDefault()
        {
            // Arrange
            NavigationPropertyConfiguration navigationProperty =
                new NavigationPropertyConfiguration(new MockPropertyInfo(), EdmMultiplicity.ZeroOrOne,
                    new EntityTypeConfiguration());

            // Act & Assert
            Assert.Equal(EdmOnDeleteAction.None, navigationProperty.OnDeleteAction);
        }
        public NavigationPropertyConfiguration AddNavigationProperty(PropertyInfo navigationProperty, EdmMultiplicity multiplicity)
        {
            if (navigationProperty == null)
            {
                throw Error.ArgumentNull("navigationProperty");
            }

            if (navigationProperty.DeclaringType != ClrType)
            {
                throw Error.Argument("navigationProperty", SRResources.PropertyDoesNotBelongToType);
            }

            PropertyConfiguration propertyConfig;
            NavigationPropertyConfiguration navigationPropertyConfig;

            if (ExplicitProperties.ContainsKey(navigationProperty))
            {
                propertyConfig = ExplicitProperties[navigationProperty];
                if (propertyConfig.Kind != PropertyKind.Navigation)
                {
                    throw Error.Argument("navigationProperty", SRResources.MustBeNavigationProperty, navigationProperty.Name);
                }

                navigationPropertyConfig = propertyConfig as NavigationPropertyConfiguration;
                if (navigationPropertyConfig.Multiplicity != multiplicity)
                {
                    throw Error.Argument("navigationProperty", SRResources.MustHaveMatchingMultiplicity, navigationProperty.Name, multiplicity);
                }
            }
            else
            {
                navigationPropertyConfig = new NavigationPropertyConfiguration(navigationProperty, multiplicity);
                ExplicitProperties[navigationProperty] = navigationPropertyConfig;
                // make sure the related type is configured
                ModelBuilder.AddEntity(navigationPropertyConfig.RelatedClrType);
            }
            return navigationPropertyConfig;
        }
        public void CascadeOnDelete_ModifiesOnDelete_WithParameter()
        {
            // Arrange
            NavigationPropertyConfiguration navigationProperty =
                new NavigationPropertyConfiguration(new MockPropertyInfo(), EdmMultiplicity.ZeroOrOne,
                    new EntityTypeConfiguration());

            // Act
            navigationProperty.CascadeOnDelete(cascade: false);

            // Assert
            Assert.Equal(EdmOnDeleteAction.None, navigationProperty.OnDeleteAction);
        }