Пример #1
0
        /// <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)
        {
            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.ProcessModelFinalized(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);
                            }
                        }
                    }
                }
            }
        }
Пример #2
0
        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)
                    {
                        if (clrType.IsSealed)
                        {
                            throw new InvalidOperationException(ProxiesStrings.ItsASeal(entityType.DisplayName()));
                        }

                        var proxyType = _proxyFactory.CreateProxyType(_options, (IEntityType)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), (IPropertyBase)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));
                            }
                        }
                    }
                }
            }
        }
Пример #3
0
        /// <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)
                    {
                        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()));
                                }
                            }
                        }
                    }
                }
            }
        }