public void Apply_should_not_discover_when_existing_constraint()
        {
            var associationType = new EdmAssociationType().Initialize();
            var associationConstraint = new EdmAssociationConstraint();

            associationType.Constraint = associationConstraint;

            ((IEdmConvention<EdmAssociationType>)new TypeNameForeignKeyDiscoveryConvention())
                .Apply(associationType, new EdmModel().Initialize());

            Assert.Same(associationConstraint, associationType.Constraint);
        }
        public void Apply_is_noop_when_existing_constraint()
        {
            var associationConstraint = new EdmAssociationConstraint();
            var navigationProperty = new EdmNavigationProperty
                {
                    Association = new EdmAssociationType
                        {
                            Constraint = associationConstraint
                        }
                };

            ((IEdmConvention<EdmNavigationProperty>)new ForeignKeyNavigationPropertyAttributeConvention())
                .Apply(navigationProperty, new EdmModel());

            Assert.Same(associationConstraint, navigationProperty.Association.Constraint);
        }
        public void Apply_should_set_principal_end_kind_to_required_when_all_properties_not_nullable()
        {
            var associationType = new EdmAssociationType().Initialize();
            associationType.SourceEnd.EntityType = new EdmEntityType();
            associationType.SourceEnd.EndKind = EdmAssociationEndKind.Optional;
            associationType.TargetEnd.EntityType = new EdmEntityType();

            var associationConstraint = new EdmAssociationConstraint();
            associationConstraint.DependentProperties.Add(new EdmProperty().AsPrimitive());
            associationConstraint.DependentProperties.Add(new EdmProperty().AsPrimitive());
            associationConstraint.DependentProperties.Each(p => p.PropertyType.IsNullable = false);
            associationConstraint.DependentEnd = associationType.TargetEnd;

            associationType.Constraint = associationConstraint;

            ((IEdmConvention<EdmAssociationType>)new ForeignKeyAssociationMultiplicityConvention())
                .Apply(associationType, new EdmModel().Initialize());

            Assert.True(associationType.SourceEnd.IsRequired());
        }
        internal override void Configure(
            EdmAssociationType associationType, EdmAssociationEnd dependentEnd,
            EntityTypeConfiguration entityTypeConfiguration)
        {
            if (!_dependentProperties.Any())
            {
                return;
            }

            var associationConstraint
                = new EdmAssociationConstraint
                    {
                        DependentEnd = dependentEnd
                    };

            var dependentProperties = _dependentProperties.AsEnumerable();

            if (!IsFullySpecified)
            {
                var foreignKeys
                    = from p in _dependentProperties
                      select new
                          {
                              PropertyInfo = p,
                              entityTypeConfiguration.Property(new PropertyPath(p)).ColumnOrder
                          };

                if ((_dependentProperties.Count > 1)
                    && foreignKeys.Any(p => !p.ColumnOrder.HasValue))
                {
                    var dependentKeys = dependentEnd.EntityType.DeclaredKeyProperties;

                    if ((dependentKeys.Count == _dependentProperties.Count)
                        &&
                        foreignKeys.All(fk => dependentKeys.Any(p => p.GetClrPropertyInfo().IsSameAs(fk.PropertyInfo))))
                    {
                        // The FK and PK sets are equal, we know the order
                        dependentProperties = dependentKeys.Select(p => p.GetClrPropertyInfo());
                    }
                    else
                    {
                        throw Error.ForeignKeyAttributeConvention_OrderRequired(entityTypeConfiguration.ClrType);
                    }
                }
                else
                {
                    dependentProperties = foreignKeys.OrderBy(p => p.ColumnOrder).Select(p => p.PropertyInfo);
                }
            }

            foreach (var dependentProperty in dependentProperties)
            {
                var property
                    = associationConstraint
                        .DependentEnd
                        .EntityType
                        .GetDeclaredPrimitiveProperty(dependentProperty);

                if (property == null)
                {
                    throw Error.ForeignKeyPropertyNotFound(
                        dependentProperty.Name, associationConstraint.DependentEnd.EntityType.Name);
                }

                associationConstraint.DependentProperties.Add(property);
            }

            associationType.Constraint = associationConstraint;

            var principalEnd = associationType.GetOtherEnd(dependentEnd);

            if (principalEnd.IsRequired())
            {
                associationType.Constraint.DependentProperties.Each(p => p.PropertyType.IsNullable = false);
            }
        }