/// <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); } }
/// <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)); } } } } } }
/// <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);
/// <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);
/// <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); } }
public override IConventionEntityType OnEntityTypeRemoved( IConventionModelBuilder modelBuilder, IConventionEntityType entityType) { Add(new OnEntityTypeRemovedNode(modelBuilder, entityType)); return(entityType); }
private bool IsNonNullable(IConventionModelBuilder modelBuilder, IConventionNavigation navigation) => navigation.DeclaringEntityType.GetRuntimeProperties().Find(navigation.Name) is PropertyInfo propertyInfo &&
/// <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);
/// <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);
/// <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); }
public OnEntityTypeIgnoredNode(IConventionModelBuilder modelBuilder, string name, Type type) { ModelBuilder = modelBuilder; Name = name; Type = type; }
/// <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); }
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]); } }
public override string OnEntityTypeIgnored(IConventionModelBuilder modelBuilder, string name, Type type) { Add(new OnEntityTypeIgnoredNode(modelBuilder, name, type)); return(name); }
/// <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); } } } }
/// <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);