public void Throws_if_non_virtual_indexer_property() { using var context = new ChangeContext <ChangeNonVirtualIndexer>(entityBuilderAction: b => b.IndexerProperty <int>("Snoopy")); Assert.Equal( ProxiesStrings.NonVirtualIndexerProperty(nameof(ChangeNonVirtualIndexer)), Assert.Throws <InvalidOperationException>(() => context.Model).Message); }
public void Throws_if_non_virtual_navigation() { using var context = new ChangeContext <ChangeNonVirtualNavEntity>(); Assert.Equal( ProxiesStrings.NonVirtualProperty(nameof(ChangeNonVirtualNavEntity.SelfRef), nameof(ChangeNonVirtualNavEntity)), Assert.Throws <InvalidOperationException>( () => context.Model).Message); }
public void Throws_if_create_proxy_when_proxies_not_enabled() { using var context = new NeweyContextN7(); Assert.Equal( ProxiesStrings.ProxiesNotEnabled(nameof(RedBullRb3)), Assert.Throws <InvalidOperationException>( () => context.CreateProxy <RedBullRb3>()).Message); }
public void Throws_if_sealed_class() { using var context = new ChangeContext <ChangeSealedEntity>(); Assert.Equal( ProxiesStrings.ItsASeal(nameof(ChangeSealedEntity)), Assert.Throws <InvalidOperationException>( () => context.Model).Message); }
public void Throws_if_non_virtual_navigation() { using var context = new NeweyContextN2(); Assert.Equal( ProxiesStrings.NonVirtualNavigation(nameof(McLarenMp419.SelfRef), nameof(McLarenMp419)), Assert.Throws <InvalidOperationException>( () => context.Model).Message); }
public void Throws_if_sealed_class() { using var context = new NeweyContextN1(); Assert.Equal( ProxiesStrings.ItsASeal(nameof(McLarenMp418)), Assert.Throws <InvalidOperationException>( () => context.Model).Message); }
private static void CheckProxyOptions(IServiceProvider serviceProvider, string entityTypeName) { var options = serviceProvider.GetRequiredService <IDbContextOptions>().FindExtension <ProxiesOptionsExtension>(); if (options?.UseProxies != true) { throw new InvalidOperationException(ProxiesStrings.ProxiesNotEnabled(entityTypeName)); } }
public void Throws_if_dictionary_type_with_additional_properties() { using var context = new SharedChangeContext <Dictionary <string, int> >(b => b.IndexerProperty <int>("Snoopy")); Assert.Equal( ProxiesStrings.DictionaryCannotBeProxied( typeof(Dictionary <string, int>).ShortDisplayName(), "STET (Dictionary<string, int>)", typeof(IDictionary <string, int>).ShortDisplayName()), Assert.Throws <InvalidOperationException>(() => context.Model).Message); }
[ConditionalFact] // Issue #22407 public void CreateProxy_throws_for_weak_entity_types() { using var context = new NeweyContext(); Assert.Equal( ProxiesStrings.EntityTypeNotFoundWeak(nameof(IsWeak)), Assert.Throws <InvalidOperationException>(() => context.CreateProxy <IsWeak>()).Message); Assert.Equal( ProxiesStrings.EntityTypeNotFoundWeak(nameof(IsWeak)), Assert.Throws <InvalidOperationException>(() => context.CreateProxy <IsWeak>(_ => { })).Message); Assert.Equal( ProxiesStrings.EntityTypeNotFoundWeak(nameof(IsWeak)), Assert.Throws <InvalidOperationException>(() => context.CreateProxy(typeof(IsWeak))).Message); }
public void CreateProxy_throws_for_shared_type_entity_types_when_entity_type_name_not_known() { using var context = new NeweyContext(); Assert.Equal( ProxiesStrings.EntityTypeNotFoundShared(nameof(SharedTypeEntityType)), Assert.Throws <InvalidOperationException>(() => context.CreateProxy <SharedTypeEntityType>()).Message); Assert.Equal( ProxiesStrings.EntityTypeNotFoundShared(nameof(SharedTypeEntityType)), Assert.Throws <InvalidOperationException>(() => context.CreateProxy <SharedTypeEntityType>(_ => { })).Message); Assert.Equal( ProxiesStrings.EntityTypeNotFoundShared(nameof(SharedTypeEntityType)), Assert.Throws <InvalidOperationException>(() => context.CreateProxy(typeof(SharedTypeEntityType))).Message); }
/// <summary> /// This API supports the Entity Framework Core infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> public virtual InternalModelBuilder Apply(InternalModelBuilder modelBuilder) { if (_options?.UseLazyLoadingProxies == true) { foreach (var entityType in modelBuilder.Metadata.GetEntityTypes()) { if (entityType.ClrType != null && !entityType.ClrType.IsAbstract) { if (entityType.ClrType.IsSealed) { throw new InvalidOperationException(ProxiesStrings.ItsASeal(entityType.DisplayName())); } var binding = (ConstructorBinding)entityType[CoreAnnotationNames.ConstructorBinding]; if (binding == null) { _directBindingConvention.Apply(modelBuilder); } binding = (ConstructorBinding)entityType[CoreAnnotationNames.ConstructorBinding]; entityType[CoreAnnotationNames.ConstructorBinding] = RewriteToFactoryBinding(binding); foreach (var navigation in entityType.GetNavigations()) { if (navigation.PropertyInfo == null) { throw new InvalidOperationException( ProxiesStrings.FieldNavigation(navigation.Name, entityType.DisplayName())); } if (!navigation.PropertyInfo.GetMethod.IsVirtual) { throw new InvalidOperationException( ProxiesStrings.NonVirtualNavigation(navigation.Name, entityType.DisplayName())); } navigation.SetPropertyAccessMode(PropertyAccessMode.Field); } } } } return(modelBuilder); }
private static object CreateProxy( this IServiceProvider serviceProvider, Type entityType, params object[] constructorArguments) { var options = serviceProvider.GetService <IDbContextOptions>().FindExtension <ProxiesOptionsExtension>(); if (options?.UseProxies != true) { throw new InvalidOperationException(ProxiesStrings.ProxiesNotEnabled(entityType.ShortDisplayName())); } return(serviceProvider.GetService <IProxyFactory>().Create( serviceProvider.GetService <ICurrentDbContext>().Context, entityType, constructorArguments)); }
/// <summary> /// Creates a proxy instance for an entity type if proxy creation has been turned on. /// </summary> /// <param name="context"> The <see cref="DbContext" />. </param> /// <param name="entityType"> The entity type for which a proxy is needed. </param> /// <param name="constructorArguments"> Arguments to pass to the entity type constructor. </param> /// <returns> The proxy instance. </returns> public static object CreateProxy( [NotNull] this DbContext context, [NotNull] Type entityType, [NotNull] params object[] constructorArguments) { Check.NotNull(context, nameof(context)); Check.NotNull(entityType, nameof(entityType)); Check.NotNull(constructorArguments, nameof(constructorArguments)); var options = context.GetService <IDbContextOptions>().FindExtension <ProxiesOptionsExtension>(); if (options?.UseLazyLoadingProxies != true) { throw new InvalidOperationException(ProxiesStrings.ProxiesNotEnabled(entityType.ShortDisplayName())); } return(context.GetService <IProxyFactory>().Create(context, entityType, constructorArguments)); }
/// <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 object Create( DbContext context, Type type, params object[] constructorArguments) { var entityType = context.Model.FindRuntimeEntityType(type); if (entityType == null) { if (context.Model.IsShared(type)) { throw new InvalidOperationException(ProxiesStrings.EntityTypeNotFoundShared(type.ShortDisplayName())); } throw new InvalidOperationException(CoreStrings.EntityTypeNotFound(type.ShortDisplayName())); } return(CreateProxy(context, entityType, constructorArguments)); }
/// <summary> /// This API supports the Entity Framework Core infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> public virtual InternalModelBuilder Apply(InternalModelBuilder modelBuilder) { if (_options?.UseLazyLoadingProxies == 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.CreateLazyLoadingProxyType(entityType); 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, ConfigurationSource.Convention); serviceProperty.SetParameterBinding( (ServiceParameterBinding) new LazyLoaderParameterBindingFactory().Bind( entityType, typeof(ILazyLoader), nameof(IProxyLazyLoader.LazyLoader))); } var binding = (ConstructorBinding)entityType[CoreAnnotationNames.ConstructorBinding]; if (binding == null) { _directBindingConvention.Apply(modelBuilder); } binding = (ConstructorBinding)entityType[CoreAnnotationNames.ConstructorBinding]; entityType[CoreAnnotationNames.ConstructorBinding] = new FactoryMethodConstructorBinding( _proxyFactory, _createLazyLoadingProxyMethod, new List <ParameterBinding> { new EntityTypeParameterBinding(), new DefaultServiceParameterBinding(typeof(ILazyLoader), typeof(ILazyLoader), serviceProperty), new ObjectArrayParameterBinding(binding.ParameterBindings) }, proxyType); foreach (var navigation in entityType.GetNavigations()) { if (navigation.PropertyInfo == null) { throw new InvalidOperationException( ProxiesStrings.FieldNavigation(navigation.Name, entityType.DisplayName())); } if (!navigation.PropertyInfo.GetMethod.IsVirtual) { throw new InvalidOperationException( ProxiesStrings.NonVirtualNavigation(navigation.Name, entityType.DisplayName())); } navigation.SetPropertyAccessMode(PropertyAccessMode.Field); } } } } return(modelBuilder); }
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)); } } } } } }
/// <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); } } } } } }
/// <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())); } } } } } } }