Exemple #1
0
 /// <inheritdoc />
 public virtual void ProcessModelInitialized(IConventionModelBuilder modelBuilder, IConventionContext <IConventionModelBuilder> context)
 => modelBuilder.HasValueGenerationStrategy(
     _postgresVersion < new Version(10, 0)
             ? NpgsqlValueGenerationStrategy.SerialColumn
             : NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
        /// <summary>
        ///     Called after a model is finalized.
        /// </summary>
        /// <param name="modelBuilder"> The builder for the model. </param>
        /// <param name="context"> Additional information associated with convention execution. </param>
        public virtual void ProcessModelFinalized(IConventionModelBuilder modelBuilder, IConventionContext <IConventionModelBuilder> context)
        {
            var model = modelBuilder.Metadata;

            foreach (var entityType in model.GetEntityTypes())
            {
                var inverseNavigations = GetInverseNavigations(entityType);
                if (inverseNavigations == null)
                {
                    continue;
                }

                foreach (var inverseNavigation in inverseNavigations.Values)
                {
                    foreach (var referencingNavigationWithAttribute in inverseNavigation.References)
                    {
                        var ambiguousInverse = FindAmbiguousInverse(
                            referencingNavigationWithAttribute.Item1,
                            referencingNavigationWithAttribute.Item2,
                            inverseNavigation.References);

                        var baseType = entityType.BaseType;
                        while (ambiguousInverse == null &&
                               baseType != null)
                        {
                            var navigationMap = GetInverseNavigations(baseType);
                            if (navigationMap != null &&
                                navigationMap.TryGetValue(inverseNavigation.Navigation.Name, out var inverseTuple))
                            {
                                var referencingNavigationsWithAttribute = inverseTuple.References;
                                ambiguousInverse = FindAmbiguousInverse(
                                    referencingNavigationWithAttribute.Item1,
                                    referencingNavigationWithAttribute.Item2,
                                    referencingNavigationsWithAttribute);
                            }

                            baseType = baseType.BaseType;
                        }

                        if (ambiguousInverse != null)
                        {
                            Dependencies.Logger.MultipleInversePropertiesSameTargetWarning(
                                new[]
                            {
                                Tuple.Create(
                                    referencingNavigationWithAttribute.Item1, referencingNavigationWithAttribute.Item2.ClrType),
                                Tuple.Create(ambiguousInverse.Value.Item1, ambiguousInverse.Value.Item2.ClrType)
                            },
                                inverseNavigation.Navigation,
                                entityType.ClrType);
                            break;
                        }
                    }
                }
            }

            foreach (var entityType in model.GetEntityTypes())
            {
                entityType.RemoveAnnotation(CoreAnnotationNames.InverseNavigations);
            }
        }
Exemple #3
0
        /// <inheritdoc />
        public virtual void ProcessModelFinalizing(IConventionModelBuilder modelBuilder, IConventionContext <IConventionModelBuilder> context)
        {
            if (_options?.UseProxies == true)
            {
                foreach (var entityType in modelBuilder.Metadata.GetEntityTypes())
                {
                    if (entityType.ClrType?.IsAbstract == false)
                    {
                        if (entityType.ClrType.IsSealed)
                        {
                            throw new InvalidOperationException(ProxiesStrings.ItsASeal(entityType.DisplayName()));
                        }

                        var proxyType = _proxyFactory.CreateProxyType(_options, entityType);

                        // WARNING: This code is EF internal; it should not be copied. See #10789 #14554
                        var binding = (InstantiationBinding)entityType[CoreAnnotationNames.ConstructorBinding];
                        if (binding == null)
                        {
                            _directBindingConvention.ProcessModelFinalizing(modelBuilder, context);
                        }

                        // WARNING: This code is EF internal; it should not be copied. See #10789 #14554
                        binding = (InstantiationBinding)entityType[CoreAnnotationNames.ConstructorBinding];

                        if (_options.UseLazyLoadingProxies)
                        {
                            foreach (var conflictingProperty in entityType.GetDerivedTypes()
                                     .SelectMany(e => e.GetDeclaredServiceProperties().Where(p => p.ClrType == typeof(ILazyLoader)))
                                     .ToList())
                            {
                                conflictingProperty.DeclaringEntityType.RemoveServiceProperty(conflictingProperty.Name);
                            }

                            var serviceProperty = entityType.GetServiceProperties().FirstOrDefault(e => e.ClrType == typeof(ILazyLoader));
                            if (serviceProperty == null)
                            {
                                serviceProperty = entityType.AddServiceProperty(_lazyLoaderProperty);
                                serviceProperty.SetParameterBinding(
                                    (ServiceParameterBinding) new LazyLoaderParameterBindingFactory(
                                        _lazyLoaderParameterBindingFactoryDependencies)
                                    .Bind(
                                        entityType,
                                        typeof(ILazyLoader),
                                        nameof(IProxyLazyLoader.LazyLoader)));
                            }

                            entityType.SetAnnotation(
                                // WARNING: This code is EF internal; it should not be copied. See #10789 #14554
                                CoreAnnotationNames.ConstructorBinding,
                                new FactoryMethodBinding(
                                    _proxyFactory,
                                    _createLazyLoadingProxyMethod,
                                    new List <ParameterBinding>
                            {
                                new DependencyInjectionParameterBinding(typeof(IDbContextOptions), typeof(IDbContextOptions)),
                                new EntityTypeParameterBinding(),
                                new DependencyInjectionParameterBinding(typeof(ILazyLoader), typeof(ILazyLoader), serviceProperty),
                                new ObjectArrayParameterBinding(binding.ParameterBindings)
                            },
                                    proxyType));
                        }
                        else
                        {
                            entityType.SetAnnotation(
                                // WARNING: This code is EF internal; it should not be copied. See #10789 #14554
                                CoreAnnotationNames.ConstructorBinding,
                                new FactoryMethodBinding(
                                    _proxyFactory,
                                    _createProxyMethod,
                                    new List <ParameterBinding>
                            {
                                new DependencyInjectionParameterBinding(typeof(IDbContextOptions), typeof(IDbContextOptions)),
                                new EntityTypeParameterBinding(),
                                new ObjectArrayParameterBinding(binding.ParameterBindings)
                            },
                                    proxyType));

                            foreach (var prop in entityType.GetProperties().Where(p => !p.IsShadowProperty()))
                            {
                                if (prop.PropertyInfo == null)
                                {
                                    throw new InvalidOperationException(
                                              ProxiesStrings.FieldProperty(prop.Name, entityType.DisplayName()));
                                }

                                if (prop.PropertyInfo.SetMethod?.IsVirtual == false)
                                {
                                    throw new InvalidOperationException(
                                              ProxiesStrings.NonVirtualProperty(prop.Name, entityType.DisplayName()));
                                }
                            }
                        }

                        foreach (var navigation in entityType.GetNavigations())
                        {
                            if (navigation.PropertyInfo == null)
                            {
                                throw new InvalidOperationException(
                                          ProxiesStrings.FieldProperty(navigation.Name, entityType.DisplayName()));
                            }

                            if (_options.UseChangeDetectionProxies &&
                                navigation.PropertyInfo.SetMethod?.IsVirtual == false)
                            {
                                throw new InvalidOperationException(
                                          ProxiesStrings.NonVirtualProperty(navigation.Name, entityType.DisplayName()));
                            }

                            if (_options.UseLazyLoadingProxies)
                            {
                                if (!navigation.PropertyInfo.GetMethod.IsVirtual)
                                {
                                    throw new InvalidOperationException(
                                              ProxiesStrings.NonVirtualProperty(navigation.Name, entityType.DisplayName()));
                                }

                                navigation.SetPropertyAccessMode(PropertyAccessMode.Field);
                            }
                        }
                    }
                }
            }
        }
 /// <summary>
 ///     Called after a model is finalized. Removes the cached state annotation used by this convention.
 /// </summary>
 /// <param name="modelBuilder"> The builder for the model. </param>
 /// <param name="context"> Additional information associated with convention execution. </param>
 public virtual void ProcessModelFinalized(IConventionModelBuilder modelBuilder, IConventionContext <IConventionModelBuilder> context)
 => modelBuilder.Metadata.RemoveAnnotation(StateAnnotationName);
        /// <inheritdoc />
        public virtual void ProcessModelFinalizing(
            IConventionModelBuilder modelBuilder,
            IConventionContext <IConventionModelBuilder> context)
        {
            if (_options?.UseProxies == true)
            {
                foreach (var entityType in modelBuilder.Metadata.GetEntityTypes())
                {
                    var clrType = entityType.ClrType;
                    if (clrType?.IsAbstract == false)
                    {
                        if (clrType.IsSealed)
                        {
                            throw new InvalidOperationException(ProxiesStrings.ItsASeal(entityType.DisplayName()));
                        }

                        var proxyType = _proxyFactory.CreateProxyType(_options, entityType);

                        // WARNING: This code is EF internal; it should not be copied. See #10789 #14554
#pragma warning disable EF1001 // Internal EF Core API usage.
                        var binding = (InstantiationBinding)entityType[CoreAnnotationNames.ConstructorBinding];
                        if (binding == null)
                        {
                            _directBindingConvention.ProcessModelFinalizing(modelBuilder, context);
                        }

                        binding = (InstantiationBinding)entityType[CoreAnnotationNames.ConstructorBinding];
                        UpdateConstructorBindings(CoreAnnotationNames.ConstructorBinding, binding);

                        binding = (InstantiationBinding)entityType[CoreAnnotationNames.ServiceOnlyConstructorBinding];
                        if (binding != null)
                        {
                            UpdateConstructorBindings(CoreAnnotationNames.ServiceOnlyConstructorBinding, binding);
                        }
#pragma warning restore EF1001 // Internal EF Core API usage.

                        foreach (var navigationBase in entityType.GetDeclaredNavigations()
                                 .Concat <IConventionNavigationBase>(entityType.GetDeclaredSkipNavigations()))
                        {
                            if (navigationBase.PropertyInfo == null)
                            {
                                throw new InvalidOperationException(
                                          ProxiesStrings.FieldProperty(navigationBase.Name, entityType.DisplayName()));
                            }

                            if (_options.UseChangeTrackingProxies &&
                                navigationBase.PropertyInfo.SetMethod?.IsReallyVirtual() == false)
                            {
                                throw new InvalidOperationException(
                                          ProxiesStrings.NonVirtualProperty(navigationBase.Name, entityType.DisplayName()));
                            }

                            if (_options.UseLazyLoadingProxies)
                            {
                                if (!navigationBase.PropertyInfo.GetMethod.IsReallyVirtual() &&
                                    (!(navigationBase is INavigation navigation &&
                                       navigation.ForeignKey.IsOwnership)))
                                {
                                    throw new InvalidOperationException(
                                              ProxiesStrings.NonVirtualProperty(navigationBase.Name, entityType.DisplayName()));
                                }

                                navigationBase.SetPropertyAccessMode(PropertyAccessMode.Field);
                            }
                        }

                        if (_options.UseChangeTrackingProxies)
                        {
                            var indexerChecked = false;
                            foreach (var property in entityType.GetDeclaredProperties()
                                     .Where(p => !p.IsShadowProperty()))
                            {
                                if (property.IsIndexerProperty())
                                {
                                    if (!indexerChecked)
                                    {
                                        indexerChecked = true;

                                        if (!property.PropertyInfo.SetMethod.IsReallyVirtual())
                                        {
                                            if (clrType.IsGenericType &&
                                                clrType.GetGenericTypeDefinition() == typeof(Dictionary <,>) &&
                                                clrType.GenericTypeArguments[0] == typeof(string))
                                            {
                                                if (entityType.GetProperties().Any(p => !p.IsPrimaryKey()))
                                                {
                                                    throw new InvalidOperationException(
                                                              ProxiesStrings.DictionaryCannotBeProxied(
                                                                  clrType.ShortDisplayName(),
                                                                  entityType.DisplayName(),
                                                                  typeof(IDictionary <,>).MakeGenericType(clrType.GenericTypeArguments)
                                                                  .ShortDisplayName()));
                                                }
                                            }
                                            else
                                            {
                                                throw new InvalidOperationException(
                                                          ProxiesStrings.NonVirtualIndexerProperty(entityType.DisplayName()));
                                            }
                                        }
                                    }
                                }
                                else
                                {
                                    if (property.PropertyInfo == null)
                                    {
                                        throw new InvalidOperationException(
                                                  ProxiesStrings.FieldProperty(property.Name, entityType.DisplayName()));
                                    }

                                    if (property.PropertyInfo.SetMethod?.IsReallyVirtual() == false)
                                    {
                                        throw new InvalidOperationException(
                                                  ProxiesStrings.NonVirtualProperty(property.Name, entityType.DisplayName()));
                                    }
                                }
                            }
                        }

                        void UpdateConstructorBindings(string bindingAnnotationName, InstantiationBinding binding)
                        {
                            if (_options.UseLazyLoadingProxies)
                            {
                                foreach (var conflictingProperty in entityType.GetDerivedTypes()
                                         .SelectMany(e => e.GetDeclaredServiceProperties().Where(p => p.ClrType == typeof(ILazyLoader)))
                                         .ToList())
                                {
                                    conflictingProperty.DeclaringEntityType.RemoveServiceProperty(conflictingProperty.Name);
                                }

                                var serviceProperty = entityType.GetServiceProperties()
                                                      .FirstOrDefault(e => e.ClrType == typeof(ILazyLoader));
                                if (serviceProperty == null)
                                {
                                    serviceProperty = entityType.AddServiceProperty(_lazyLoaderProperty);
                                    serviceProperty.SetParameterBinding(
                                        (ServiceParameterBinding) new LazyLoaderParameterBindingFactory(
                                            _lazyLoaderParameterBindingFactoryDependencies)
                                        .Bind(
                                            entityType,
                                            typeof(ILazyLoader),
                                            nameof(IProxyLazyLoader.LazyLoader)));
                                }

                                entityType.SetAnnotation(
                                    bindingAnnotationName,
                                    new FactoryMethodBinding(
                                        _proxyFactory,
                                        _createLazyLoadingProxyMethod,
                                        new List <ParameterBinding>
                                {
                                    new ContextParameterBinding(typeof(DbContext)),
                                    new EntityTypeParameterBinding(),
                                    new DependencyInjectionParameterBinding(
                                        typeof(ILazyLoader), typeof(ILazyLoader), serviceProperty),
                                    new ObjectArrayParameterBinding(binding.ParameterBindings)
                                },
                                        proxyType));
                            }
                            else
                            {
                                entityType.SetAnnotation(
                                    bindingAnnotationName,
                                    new FactoryMethodBinding(
                                        _proxyFactory,
                                        _createProxyMethod,
                                        new List <ParameterBinding>
                                {
                                    new ContextParameterBinding(typeof(DbContext)),
                                    new EntityTypeParameterBinding(),
                                    new ObjectArrayParameterBinding(binding.ParameterBindings)
                                },
                                        proxyType));
                            }
                        }
                    }
                }
            }
        }
Exemple #6
0
 /// <summary>
 ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
 ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
 ///     any release. You should only use it directly in your code with extreme caution and knowing that
 ///     doing so can result in application failures when updating to a new Entity Framework Core release.
 /// </summary>
 public virtual IConventionEntityType OnEntityTypeRemoved(
     [NotNull] IConventionModelBuilder modelBuilder, [NotNull] IConventionEntityType type)
 => _scope.OnEntityTypeRemoved(modelBuilder, type);
Exemple #7
0
 /// <summary>
 ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
 ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
 ///     any release. You should only use it directly in your code with extreme caution and knowing that
 ///     doing so can result in application failures when updating to a new Entity Framework Core release.
 /// </summary>
 public virtual IConventionModelBuilder OnModelFinalizing([NotNull] IConventionModelBuilder modelBuilder)
 => _immediateConventionScope.OnModelFinalizing(modelBuilder);
 /// <summary>
 ///     Returns a value indicating whether the given value can be set as the service tier of the database.
 /// </summary>
 /// <remarks>
 ///     See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see>, and
 ///     <see href="https://aka.ms/efcore-docs-sqlserver">Accessing SQL Server and SQL Azure databases with EF Core</see>
 ///     for more information and examples.
 /// </remarks>
 /// <param name="modelBuilder">The model builder.</param>
 /// <param name="serviceTier">The expression for the service tier of the database.</param>
 /// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
 /// <returns><see langword="true" /> if the given value can be set as the service tier of the database.</returns>
 public static bool CanSetServiceTierSql(
     this IConventionModelBuilder modelBuilder,
     string?serviceTier,
     bool fromDataAnnotation = false)
 => modelBuilder.CanSetAnnotation(SqlServerAnnotationNames.ServiceTierSql, serviceTier, fromDataAnnotation);
 /// <summary>
 ///     Returns a value indicating whether the given value can be set as the performance level of the database.
 /// </summary>
 /// <remarks>
 ///     See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see>, and
 ///     <see href="https://aka.ms/efcore-docs-sqlserver">Accessing SQL Server and SQL Azure databases with EF Core</see>
 ///     for more information and examples.
 /// </remarks>
 /// <param name="modelBuilder">The model builder.</param>
 /// <param name="performanceLevel">The performance level of the database expression.</param>
 /// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
 /// <returns><see langword="true" /> if the given value can be set as the performance level of the database.</returns>
 public static bool CanSetPerformanceLevelSql(
     this IConventionModelBuilder modelBuilder,
     string?performanceLevel,
     bool fromDataAnnotation = false)
 => modelBuilder.CanSetAnnotation(SqlServerAnnotationNames.PerformanceLevelSql, performanceLevel, fromDataAnnotation);
 /// <summary>
 ///     Returns a value indicating whether the given value can be set as the default value generation strategy.
 /// </summary>
 /// <remarks>
 ///     See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see>, and
 ///     <see href="https://aka.ms/efcore-docs-sqlserver">Accessing SQL Server and SQL Azure databases with EF Core</see>
 ///     for more information and examples.
 /// </remarks>
 /// <param name="modelBuilder">The model builder.</param>
 /// <param name="valueGenerationStrategy">The value generation strategy.</param>
 /// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
 /// <returns><see langword="true" /> if the given value can be set as the default value generation strategy.</returns>
 public static bool CanSetValueGenerationStrategy(
     this IConventionModelBuilder modelBuilder,
     SqlServerValueGenerationStrategy?valueGenerationStrategy,
     bool fromDataAnnotation = false)
 => modelBuilder.CanSetAnnotation(
     SqlServerAnnotationNames.ValueGenerationStrategy, valueGenerationStrategy, fromDataAnnotation);
 /// <summary>
 ///     Returns a value indicating whether the given value can be set as the maximum size of the database.
 /// </summary>
 /// <remarks>
 ///     See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see>, and
 ///     <see href="https://aka.ms/efcore-docs-sqlserver">Accessing SQL Server and SQL Azure databases with EF Core</see>
 ///     for more information and examples.
 /// </remarks>
 /// <param name="modelBuilder">The model builder.</param>
 /// <param name="maxSize">The maximum size of the database.</param>
 /// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
 /// <returns><see langword="true" /> if the given value can be set as the maximum size of the database.</returns>
 public static bool CanSetDatabaseMaxSize(
     this IConventionModelBuilder modelBuilder,
     string?maxSize,
     bool fromDataAnnotation = false)
 => modelBuilder.CanSetAnnotation(SqlServerAnnotationNames.MaxDatabaseSize, maxSize, fromDataAnnotation);
 /// <summary>
 ///     Returns a value indicating whether the given value can be set as the default increment for SQL Server IDENTITY.
 /// </summary>
 /// <remarks>
 ///     See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see>, and
 ///     <see href="https://aka.ms/efcore-docs-sqlserver">Accessing SQL Server and SQL Azure databases with EF Core</see>
 ///     for more information and examples.
 /// </remarks>
 /// <param name="modelBuilder">The model builder.</param>
 /// <param name="increment">The incremental value that is added to the identity value of the previous row that was loaded.</param>
 /// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
 /// <returns><see langword="true" /> if the given value can be set as the default increment for SQL Server IDENTITY.</returns>
 public static bool CanSetIdentityColumnIncrement(
     this IConventionModelBuilder modelBuilder,
     int?increment,
     bool fromDataAnnotation = false)
 => modelBuilder.CanSetAnnotation(SqlServerAnnotationNames.IdentityIncrement, increment, fromDataAnnotation);
 /// <summary>
 ///     Returns a value indicating whether the given value can be set as the default seed for SQL Server IDENTITY.
 /// </summary>
 /// <remarks>
 ///     See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see>, and
 ///     <see href="https://aka.ms/efcore-docs-sqlserver">Accessing SQL Server and SQL Azure databases with EF Core</see>
 ///     for more information and examples.
 /// </remarks>
 /// <param name="modelBuilder">The model builder.</param>
 /// <param name="seed">The value that is used for the very first row loaded into the table.</param>
 /// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
 /// <returns><see langword="true" /> if the given value can be set as the seed for SQL Server IDENTITY.</returns>
 public static bool CanSetIdentityColumnSeed(
     this IConventionModelBuilder modelBuilder,
     long?seed,
     bool fromDataAnnotation = false)
 => modelBuilder.CanSetAnnotation(SqlServerAnnotationNames.IdentitySeed, seed, fromDataAnnotation);
Exemple #14
0
        /// <inheritdoc />
        public virtual void ProcessModelFinalizing(
            IConventionModelBuilder modelBuilder, IConventionContext <IConventionModelBuilder> context)
        {
            foreach (var entityType in modelBuilder.Metadata.GetEntityTypes())
            {
                foreach (var property in entityType.GetDeclaredProperties())
                {
                    NpgsqlValueGenerationStrategy?strategy = null;
                    var table = entityType.GetTableName();
                    if (table != null)
                    {
                        var storeObject = StoreObjectIdentifier.Table(table, entityType.GetSchema());
                        strategy = property.GetValueGenerationStrategy(storeObject, Dependencies.TypeMappingSource);
                        if (strategy == NpgsqlValueGenerationStrategy.None &&
                            !IsStrategyNoneNeeded(property, storeObject))
                        {
                            strategy = null;
                        }
                    }
                    else
                    {
                        var view = entityType.GetViewName();
                        if (view != null)
                        {
                            var storeObject = StoreObjectIdentifier.View(view, entityType.GetViewSchema());
                            strategy = property.GetValueGenerationStrategy(storeObject, Dependencies.TypeMappingSource);
                            if (strategy == NpgsqlValueGenerationStrategy.None &&
                                !IsStrategyNoneNeeded(property, storeObject))
                            {
                                strategy = null;
                            }
                        }
                    }

                    // Needed for the annotation to show up in the model snapshot
                    if (strategy != null)
                    {
                        property.Builder.HasValueGenerationStrategy(strategy);
                    }
                }
            }

            bool IsStrategyNoneNeeded(IReadOnlyProperty property, StoreObjectIdentifier storeObject)
            {
                if (property.ValueGenerated == ValueGenerated.OnAdd &&
                    !property.TryGetDefaultValue(storeObject, out _) &&
                    property.GetDefaultValueSql(storeObject) == null &&
                    property.GetComputedColumnSql(storeObject) == null &&
                    property.DeclaringEntityType.Model.GetValueGenerationStrategy() != NpgsqlValueGenerationStrategy.None)
                {
                    var providerClrType = (property.GetValueConverter()
                                           ?? (property.FindRelationalTypeMapping(storeObject)
                                               ?? Dependencies.TypeMappingSource.FindMapping((IProperty)property))?.Converter)
                                          ?.ProviderClrType.UnwrapNullableType();

                    return(providerClrType != null && (providerClrType.IsInteger()));
                }

                return(false);
            }
        }
Exemple #15
0
 public override IConventionEntityType OnEntityTypeRemoved(
     IConventionModelBuilder modelBuilder, IConventionEntityType entityType)
 {
     Add(new OnEntityTypeRemovedNode(modelBuilder, entityType));
     return(entityType);
 }
Exemple #16
0
 private bool IsNonNullable(IConventionModelBuilder modelBuilder, IConventionNavigation navigation)
 => navigation.DeclaringEntityType.GetRuntimeProperties().Find(navigation.Name) is PropertyInfo propertyInfo &&
Exemple #17
0
 /// <summary>
 ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
 ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
 ///     any release. You should only use it directly in your code with extreme caution and knowing that
 ///     doing so can result in application failures when updating to a new Entity Framework Core release.
 /// </summary>
 public virtual string OnEntityTypeIgnored(
     [NotNull] IConventionModelBuilder modelBuilder, [NotNull] string name, [CanBeNull] Type type)
 => _scope.OnEntityTypeIgnored(modelBuilder, name, type);
Exemple #18
0
 /// <summary>
 /// Sets the default character set to use for the model/database.
 /// </summary>
 /// <param name="modelBuilder">The model builder.</param>
 /// <param name="charSet">The character set to use.</param>
 /// <param name="delegationModes">
 /// Finely controls where to recursively apply the character set and where not (including this model/database).
 /// Implicitly uses <see cref="DelegationModes.ApplyToAll"/> if set to <see langword="null"/>.
 /// </param>
 /// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
 /// <returns>
 ///     The same builder instance if the configuration was applied,
 ///     <see langword="null" /> otherwise.
 /// </returns>
 public static IConventionModelBuilder HasCharSet(
     [NotNull] this IConventionModelBuilder modelBuilder,
     [CanBeNull] CharSet charSet,
     DelegationModes?delegationModes = null,
     bool fromDataAnnotation         = false)
 => modelBuilder.HasCharSet(charSet?.Name, delegationModes, fromDataAnnotation);
Exemple #19
0
 /// <summary>
 ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
 ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
 ///     any release. You should only use it directly in your code with extreme caution and knowing that
 ///     doing so can result in application failures when updating to a new Entity Framework Core release.
 /// </summary>
 public virtual IConventionModelBuilder OnModelInitialized([NotNull] IConventionModelBuilder modelBuilder)
 => _immediateConventionScope.OnModelInitialized(modelBuilder);
        /// <summary>
        ///     Returns a value indicating whether the member type is a non-nullable reference type.
        /// </summary>
        /// <param name="modelBuilder"> The model builder used to build the model. </param>
        /// <param name="memberInfo"> The member info. </param>
        /// <returns> <c>true</c> if the member type is a non-nullable reference type. </returns>
        protected virtual bool IsNonNullableRefType(
            [NotNull] IConventionModelBuilder modelBuilder,
            [NotNull] MemberInfo memberInfo)
        {
            if (memberInfo.GetMemberType().IsValueType)
            {
                return(false);
            }

            var state = GetOrInitializeState(modelBuilder);

            // For C# 8.0 nullable types, the C# currently synthesizes a NullableAttribute that expresses nullability into assemblies
            // it produces. If the model is spread across more than one assembly, there will be multiple versions of this attribute,
            // so look for it by name, caching to avoid reflection on every check.
            // Note that this may change - if https://github.com/dotnet/corefx/issues/36222 is done we can remove all of this.

            // First look for NullableAttribute on the member itself
            if (Attribute.GetCustomAttributes(memberInfo)
                .FirstOrDefault(a => a.GetType().FullName == NullableAttributeFullName) is Attribute attribute)
            {
                var attributeType = attribute.GetType();

                if (attributeType != state.NullableAttrType)
                {
                    state.NullableFlagsFieldInfo = attributeType.GetField("NullableFlags");
                    state.NullableAttrType       = attributeType;
                }

                if (state.NullableFlagsFieldInfo?.GetValue(attribute) is byte[] flags)
                {
                    return(flags.FirstOrDefault() == 1);
                }
            }

            // No attribute on the member, try to find a NullableContextAttribute on the declaring type
            var type = memberInfo.DeclaringType;

            if (type != null)
            {
                if (state.TypeNonNullabilityContextCache.TryGetValue(type, out var cachedTypeNonNullable))
                {
                    return(cachedTypeNonNullable);
                }

                var typeContextFlag = GetNullabilityContextFlag(state, Attribute.GetCustomAttributes(type));
                if (typeContextFlag.HasValue)
                {
                    return(state.TypeNonNullabilityContextCache[type] = typeContextFlag.Value == 1);
                }
            }

            // Not found at the type level, try at the module level
            var module = memberInfo.Module;

            if (!state.ModuleNonNullabilityContextCache.TryGetValue(module, out var moduleNonNullable))
            {
                var moduleContextFlag = GetNullabilityContextFlag(state, Attribute.GetCustomAttributes(memberInfo.Module));
                moduleNonNullable = state.ModuleNonNullabilityContextCache[module] =
                    moduleContextFlag.HasValue && moduleContextFlag == 1;
            }

            if (type != null)
            {
                state.TypeNonNullabilityContextCache[type] = moduleNonNullable;
            }

            return(moduleNonNullable);
        }
 private NonNullabilityConventionState GetOrInitializeState(IConventionModelBuilder modelBuilder)
 => (NonNullabilityConventionState)(
     modelBuilder.Metadata.FindAnnotation(StateAnnotationName)
     ?? modelBuilder.Metadata.AddAnnotation(StateAnnotationName, new NonNullabilityConventionState())
     ).Value;
        public virtual void ProcessModelFinalizing(
            IConventionModelBuilder modelBuilder,
            IConventionContext <IConventionModelBuilder> context)
        {
            if (_options?.UseProxies == true)
            {
                foreach (var entityType in modelBuilder.Metadata.GetEntityTypes())
                {
                    var clrType = entityType.ClrType;
                    if (clrType.IsAbstract)
                    {
                        continue;
                    }

                    if (clrType.IsSealed)
                    {
                        throw new InvalidOperationException(ProxiesStrings.ItsASeal(entityType.DisplayName()));
                    }

                    var proxyType = _proxyFactory.CreateProxyType(_options, entityType);

                    // WARNING: This code is EF internal; it should not be copied. See #10789 #14554
#pragma warning disable EF1001 // Internal EF Core API usage.
                    var binding = ((EntityType)entityType).ConstructorBinding;
                    if (binding == null)
                    {
                        _directBindingConvention.ProcessModelFinalizing(modelBuilder, context);
                        binding = ((EntityType)entityType).ConstructorBinding !;
                    }

                    ((EntityType)entityType).SetConstructorBinding(
                        UpdateConstructorBindings(entityType, proxyType, binding),
                        ConfigurationSource.Convention);

                    binding = ((EntityType)entityType).ServiceOnlyConstructorBinding;
                    if (binding != null)
                    {
                        ((EntityType)entityType).SetServiceOnlyConstructorBinding(
                            UpdateConstructorBindings(entityType, proxyType, binding),
                            ConfigurationSource.Convention);
                    }
#pragma warning restore EF1001 // Internal EF Core API usage.

                    foreach (var navigationBase in entityType.GetDeclaredNavigations()
                             .Concat <IConventionNavigationBase>(entityType.GetDeclaredSkipNavigations()))
                    {
                        if (navigationBase.PropertyInfo == null)
                        {
                            throw new InvalidOperationException(
                                      ProxiesStrings.FieldProperty(navigationBase.Name, entityType.DisplayName()));
                        }

                        if (_options.UseChangeTrackingProxies &&
                            navigationBase.PropertyInfo.SetMethod?.IsReallyVirtual() == false)
                        {
                            throw new InvalidOperationException(
                                      ProxiesStrings.NonVirtualProperty(navigationBase.Name, entityType.DisplayName()));
                        }

                        if (_options.UseLazyLoadingProxies)
                        {
                            if (!navigationBase.PropertyInfo.GetMethod.IsReallyVirtual() &&
                                (!(navigationBase is INavigation navigation &&
                                   navigation.ForeignKey.IsOwnership)))
                            {
                                throw new InvalidOperationException(
                                          ProxiesStrings.NonVirtualProperty(navigationBase.Name, entityType.DisplayName()));
                            }

                            navigationBase.SetPropertyAccessMode(PropertyAccessMode.Field);
                        }
                    }

                    if (_options.UseChangeTrackingProxies)
                    {
                        var indexerChecked = false;
                        foreach (var property in entityType.GetDeclaredProperties()
                                 .Where(p => !p.IsShadowProperty()))
                        {
                            if (property.IsIndexerProperty())
                            {
                                if (!indexerChecked)
                                {
                                    indexerChecked = true;

                                    if (!property.PropertyInfo !.SetMethod.IsReallyVirtual())
                                    {
                                        if (clrType.IsGenericType &&
                                            clrType.GetGenericTypeDefinition() == typeof(Dictionary <,>) &&
                                            clrType.GenericTypeArguments[0] == typeof(string))
                                        {
                                            if (entityType.GetProperties().Any(p => !p.IsPrimaryKey()))
                                            {
                                                throw new InvalidOperationException(
                                                          ProxiesStrings.DictionaryCannotBeProxied(
                                                              clrType.ShortDisplayName(),
                                                              entityType.DisplayName(),
                                                              typeof(IDictionary <,>).MakeGenericType(clrType.GenericTypeArguments)
                                                              .ShortDisplayName()));
                                            }
                                        }
                                        else
                                        {
                                            throw new InvalidOperationException(
                                                      ProxiesStrings.NonVirtualIndexerProperty(entityType.DisplayName()));
                                        }
                                    }
                                }
                            }
                            else
                            {
                                if (property.PropertyInfo == null)
                                {
                                    throw new InvalidOperationException(
                                              ProxiesStrings.FieldProperty(property.Name, entityType.DisplayName()));
                                }

                                if (property.PropertyInfo.SetMethod?.IsReallyVirtual() == false)
                                {
                                    throw new InvalidOperationException(
                                              ProxiesStrings.NonVirtualProperty(property.Name, entityType.DisplayName()));
                                }
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        ///     Returns a value indicating whether the member type is a non-nullable reference type.
        /// </summary>
        /// <param name="modelBuilder"> The model builder used to build the model. </param>
        /// <param name="memberInfo"> The member info. </param>
        /// <returns> <c>true</c> if the member type is a non-nullable reference type. </returns>
        protected virtual bool IsNonNullableReferenceType(
            [JetbrainsNotNull] IConventionModelBuilder modelBuilder,
            [JetbrainsNotNull] MemberInfo memberInfo)
        {
            if (memberInfo.GetMemberType().IsValueType)
            {
                return(false);
            }

            var state = GetOrInitializeState(modelBuilder);

            // First check for [MaybeNull] on the return value. If it exists, the member is nullable.
            var isMaybeNull = memberInfo switch
            {
                FieldInfo f => f.GetCustomAttribute <MaybeNullAttribute>() != null,
                PropertyInfo p => p.GetMethod?.ReturnParameter?.GetCustomAttribute <MaybeNullAttribute>() != null,
                _ => false
            };

            if (isMaybeNull)
            {
                return(false);
            }

            // For C# 8.0 nullable types, the C# currently synthesizes a NullableAttribute that expresses nullability into assemblies
            // it produces. If the model is spread across more than one assembly, there will be multiple versions of this attribute,
            // so look for it by name, caching to avoid reflection on every check.
            // Note that this may change - if https://github.com/dotnet/corefx/issues/36222 is done we can remove all of this.

            // First look for NullableAttribute on the member itself
            if (Attribute.GetCustomAttributes(memberInfo)
                .FirstOrDefault(a => a.GetType().FullName == NullableAttributeFullName) is Attribute attribute)
            {
                var attributeType = attribute.GetType();

                if (attributeType != state.NullableAttrType)
                {
                    state.NullableFlagsFieldInfo = attributeType.GetField("NullableFlags");
                    state.NullableAttrType       = attributeType;
                }

                if (state.NullableFlagsFieldInfo?.GetValue(attribute) is byte[] flags)
                {
                    return(flags.FirstOrDefault() == 1);
                }
            }

            // No attribute on the member, try to find a NullableContextAttribute on the declaring type
            var type = memberInfo.DeclaringType;

            if (type != null)
            {
                if (state.TypeCache.TryGetValue(type, out var cachedTypeNonNullable))
                {
                    return(cachedTypeNonNullable);
                }

                if (Attribute.GetCustomAttributes(type)
                    .FirstOrDefault(a => a.GetType().FullName == NullableContextAttributeFullName) is Attribute contextAttr)
                {
                    var attributeType = contextAttr.GetType();

                    if (attributeType != state.NullableContextAttrType)
                    {
                        state.NullableContextFlagFieldInfo = attributeType.GetField("Flag");
                        state.NullableContextAttrType      = attributeType;
                    }

                    if (state.NullableContextFlagFieldInfo?.GetValue(contextAttr) is byte flag)
                    {
                        return(state.TypeCache[type] = flag == 1);
                    }
                }

                return(state.TypeCache[type] = false);
            }

            return(false);
        }
Exemple #24
0
 public OnEntityTypeIgnoredNode(IConventionModelBuilder modelBuilder, string name, Type type)
 {
     ModelBuilder = modelBuilder;
     Name         = name;
     Type         = type;
 }
Exemple #25
0
 /// <summary>
 ///     Called after a model is initialized.
 /// </summary>
 /// <param name="modelBuilder">The builder for the model.</param>
 /// <param name="context">Additional information associated with convention execution.</param>
 public virtual void ProcessModelInitialized(
     IConventionModelBuilder modelBuilder,
     IConventionContext <IConventionModelBuilder> context)
 {
     modelBuilder.Metadata.Builder.HasMaxIdentifierLength(MaxIdentifierLength);
 }
Exemple #26
0
 public OnEntityTypeRemovedNode(IConventionModelBuilder modelBuilder, IConventionEntityType entityType)
 {
     ModelBuilder = modelBuilder;
     EntityType   = entityType;
 }
        /// <inheritdoc />
        public virtual void ProcessModelFinalizing(
            IConventionModelBuilder modelBuilder,
            IConventionContext<IConventionModelBuilder> context)
        {
            foreach (var entityType in modelBuilder.Metadata.GetEntityTypes())
            {
                if (entityType.ClrType?.IsAbstract == false
                    && entityType.Builder.CanSetAnnotation(CoreAnnotationNames.ConstructorBinding, null))
                {
                    var maxServiceParams = 0;
                    var maxServiceOnlyParams = 0;
                    var minPropertyParams = int.MaxValue;
                    var foundBindings = new List<InstantiationBinding>();
                    var foundServiceOnlyBindings = new List<InstantiationBinding>();
                    var bindingFailures = new List<IEnumerable<ParameterInfo>>();

                    foreach (var constructor in entityType.ClrType.GetTypeInfo()
                        .DeclaredConstructors
                        .Where(c => !c.IsStatic))
                    {
                        // Trying to find the constructor with the most service properties
                        // followed by the least scalar property parameters
                        if (Dependencies.ConstructorBindingFactory.TryBindConstructor(
                            entityType, constructor, out var binding, out var failures))
                        {
                            var serviceParamCount = binding.ParameterBindings.OfType<ServiceParameterBinding>().Count();
                            var propertyParamCount = binding.ParameterBindings.Count - serviceParamCount;

                            if (propertyParamCount == 0)
                            {
                                if (serviceParamCount == maxServiceOnlyParams)
                                {
                                    foundServiceOnlyBindings.Add(binding);
                                }
                                else if (serviceParamCount > maxServiceOnlyParams)
                                {
                                    foundServiceOnlyBindings.Clear();
                                    foundServiceOnlyBindings.Add(binding);

                                    maxServiceOnlyParams = serviceParamCount;
                                }
                            }

                            if (serviceParamCount == maxServiceParams
                                && propertyParamCount == minPropertyParams)
                            {
                                foundBindings.Add(binding);
                            }
                            else if (serviceParamCount > maxServiceParams)
                            {
                                foundBindings.Clear();
                                foundBindings.Add(binding);

                                maxServiceParams = serviceParamCount;
                                minPropertyParams = propertyParamCount;
                            }
                            else if (propertyParamCount < minPropertyParams)
                            {
                                foundBindings.Clear();
                                foundBindings.Add(binding);

                                maxServiceParams = serviceParamCount;
                                minPropertyParams = propertyParamCount;
                            }
                        }
                        else
                        {
                            bindingFailures.Add(failures);
                        }
                    }

                    if (foundBindings.Count == 0)
                    {
                        var constructorErrors = bindingFailures.SelectMany(f => f)
                            .GroupBy(f => f.Member as ConstructorInfo)
                            .Select(
                                x => CoreStrings.ConstructorBindingFailed(
                                    string.Join("', '", x.Select(f => f.Name)),
                                    entityType.DisplayName()
                                    + "("
                                    + string.Join(
                                        ", ", x.Key.GetParameters().Select(
                                            y => y.ParameterType.ShortDisplayName() + " " + y.Name)
                                    )
                                    + ")"
                                )
                            );

                        throw new InvalidOperationException(
                            CoreStrings.ConstructorNotFound(
                                entityType.DisplayName(),
                                string.Join("; ", constructorErrors)));
                    }

                    if (foundBindings.Count > 1)
                    {
                        throw new InvalidOperationException(
                            CoreStrings.ConstructorConflict(
                                FormatConstructorString(entityType, foundBindings[0]),
                                FormatConstructorString(entityType, foundBindings[1])));
                    }

                    entityType.Builder.HasAnnotation(
                        CoreAnnotationNames.ConstructorBinding,
                        foundBindings[0]);

                    if (foundServiceOnlyBindings.Count == 1)
                    {
                        entityType.Builder.HasAnnotation(
                            CoreAnnotationNames.ServiceOnlyConstructorBinding,
                            foundServiceOnlyBindings[0]);
                    }
                }
Exemple #28
0
 public override string OnEntityTypeIgnored(IConventionModelBuilder modelBuilder, string name, Type type)
 {
     Add(new OnEntityTypeIgnoredNode(modelBuilder, name, type));
     return(name);
 }
Exemple #29
0
    /// <inheritdoc />
    public virtual void ProcessModelFinalizing(
        IConventionModelBuilder modelBuilder,
        IConventionContext <IConventionModelBuilder> context)
    {
        var tableToEntityTypes = new Dictionary <(string Name, string?Schema), List <IConventionEntityType> >();

        foreach (var entityType in modelBuilder.Metadata.GetEntityTypes())
        {
            var tableName = entityType.GetTableName();
            if (tableName == null)
            {
                continue;
            }

            var table = (tableName, entityType.GetSchema());
            if (!tableToEntityTypes.TryGetValue(table, out var mappedTypes))
            {
                mappedTypes = new List <IConventionEntityType>();
                tableToEntityTypes[table] = mappedTypes;
            }

            mappedTypes.Add(entityType);
        }

        foreach (var tableToEntityType in tableToEntityTypes)
        {
            var table       = tableToEntityType.Key;
            var mappedTypes = tableToEntityType.Value;

            var concurrencyColumns = GetConcurrencyTokensMap(StoreObjectIdentifier.Table(table.Name, table.Schema), mappedTypes);
            if (concurrencyColumns == null)
            {
                continue;
            }

            foreach (var concurrencyColumn in concurrencyColumns)
            {
                var concurrencyColumnName = concurrencyColumn.Key;
                var propertiesMappedToConcurrencyColumn = concurrencyColumn.Value;

                Dictionary <IConventionEntityType, IReadOnlyProperty>?entityTypesMissingConcurrencyColumn = null;
                foreach (var entityType in mappedTypes)
                {
                    var foundMappedProperty = !IsConcurrencyTokenMissing(propertiesMappedToConcurrencyColumn, entityType, mappedTypes) ||
                                              entityType.GetProperties()
                                              .Any(p => p.GetColumnName(StoreObjectIdentifier.Table(table.Name, table.Schema)) == concurrencyColumnName);

                    if (!foundMappedProperty)
                    {
                        if (entityTypesMissingConcurrencyColumn == null)
                        {
                            entityTypesMissingConcurrencyColumn = new Dictionary <IConventionEntityType, IReadOnlyProperty>();
                        }

                        // store the entity type which is missing the
                        // concurrency token property, mapped to an example
                        // property which _is_ mapped to this concurrency token
                        // column and which will be used later as a template
                        entityTypesMissingConcurrencyColumn.Add(
                            entityType, propertiesMappedToConcurrencyColumn.First());
                    }
                }

                if (entityTypesMissingConcurrencyColumn == null)
                {
                    continue;
                }

                RemoveDerivedEntityTypes(entityTypesMissingConcurrencyColumn);

                foreach (var entityTypeToExampleProperty in entityTypesMissingConcurrencyColumn)
                {
                    var exampleProperty = entityTypeToExampleProperty.Value;
                    entityTypeToExampleProperty.Key.Builder.CreateUniqueProperty(
                        exampleProperty.ClrType,
                        ConcurrencyPropertyPrefix + exampleProperty.Name,
                        !exampleProperty.IsNullable) !
                    .HasColumnName(concurrencyColumnName) !
                    .HasColumnType(exampleProperty.GetColumnType()) !
                    .IsConcurrencyToken(true) !
                    .ValueGenerated(exampleProperty.ValueGenerated);
                }
            }
        }
    }
Exemple #30
0
 /// <summary>
 ///     Returns a value indicating whether the given character set can be set as default.
 /// </summary>
 /// <param name="modelBuilder"> The model builder. </param>
 /// <param name="charSet"> The character set. </param>
 /// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
 /// <returns> <see langword="true" /> if the given character set can be set as default. </returns>
 public static bool CanSetCharSet(
     [NotNull] this IConventionModelBuilder modelBuilder,
     [CanBeNull] CharSet charSet,
     bool fromDataAnnotation = false)
 => modelBuilder.CanSetCharSet(charSet?.Name, fromDataAnnotation);