question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

NotMapped property's entitytype getting added to modelBuilder.Model

See original GitHub issue

I’ve encountered a strange problem after upgrading to EF core 6 from EF core 5 with entity types added to the modelBuilder.Model which are annotated with the NotMapped attribute.

EF Core version: 6.0.0 (offical) + 6.0.0-rtm.21519.8 (daily) Database provider: Microsoft.EntityFrameworkCore.SqlServer Target framework: .NET 6.0 Visual Studio 2022 17.0.0

Example project Ef-Test.zip

This happens e.g. after an add-migration via the package manager console. I have added Debugger.Launch + .Break in the MyDbContext for debugging.

The problem here is, that I’ve three entities in MyDbContext (ImportPerformance, ScreenContentCountry and TrackPerformanceView) and another entity (not included in ‘MyDbContext’ (Auditorium)) which is referenced by the TrackPerformanceView with the NotMapped attribute.

Even though the NotMapped attribute is set, the created modelBuilder.Model contains the EntityType ‘Auditorium’. This doesn’t happen after downgrading to EF Core 5.X.

In one of our projects with multiple datacontexts this leads to an exception on building a datacontext model.

System.InvalidOperationException: Unable to determine the relationship represented by navigation 'TestCluster.MainClusterSystemUsers' of type 'ICollection<SystemUser>'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.ValidatePropertyMapping(IModel model, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.SqlServer.Infrastructure.Internal.SqlServerModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelRuntimeInitializer.Initialize(IModel model, Boolean designTime, IDiagnosticsLogger`1 validationLogger)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, ModelCreationDependencies modelCreationDependencies, Boolean designTime)
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel(Boolean designTime)
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
   at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__8_4(IServiceProvider p)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass2_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
   at Microsoft.EntityFrameworkCore.DbContext.get_ContextServices()
   at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
   at Microsoft.EntityFrameworkCore.DbContext.Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure<System.IServiceProvider>.get_Instance()
   at Microsoft.EntityFrameworkCore.Infrastructure.Internal.InfrastructureExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Infrastructure.AccessorExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(Func`1 factory)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(String contextType)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)

Couldn’t reproduce this easily in the example project, but I guess the error with this relies on the fact that the NotMapped property entitytypes (which are in another datacontext) get added to the model of the wrong datacontext without defining the relation via the fluent api in OnModelCreating.

To get back to the example project:

MyDbContext

public class MyDbContext : DbContext
    {
        public MyDbContext()
        {
            Debugger.Launch();
        }

        public virtual DbSet<ImportPerformance> ImportPerformances { get; set; }

        public virtual DbSet<ScreenContentCountry> ScreenContentCountries { get; set; }

        public virtual DbSet<TrackPerformanceView> TrackPerformanceViews { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer("data source=.\\SQLExpress01;initial catalog=TestDb;integrated security=True;MultipleActiveResultSets=True; Pooling=true");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            var allEntityTypes = modelBuilder.Model.GetEntityTypes().ToList();

            //get all not mapped entity types by checking the namespace
            //this should return no entitytypes, as they should be ignored
            var notMappedEntityTypes = modelBuilder.Model.GetEntityTypes().Where(t => t.Name.StartsWith("Ef_Test.NotMapped")).ToList();

            Debugger.Break();

            //throw new Exception();

            base.OnModelCreating(modelBuilder);
        }
    }

DataContext Entities: ImportPerformance

[Table("ImportPerformances", Schema = "BoxOfficeDispo")]
    public class ImportPerformance
    {
        [Key]
        public Guid Id { get; set; }

        //Adding NotMapped here leads to a correct Model in the DataContext (Ef_Test.NotMapped.Auditorium will not be added to the model)
        //[NotMapped]
        [ForeignKey("Id")]
        public TrackPerformanceView TrackPerformanceView { get; set; }

    }

ScreenContentCountry

[Table("ScreenContentCountries", Schema = "BoxOfficeDispo")]
	public class ScreenContentCountry
	{
		[Key]
		public Guid Id { get; set; }

		//Adding this navigation leads to a correct Model in the DataContext (Ef_Test.NotMapped.Auditorium will not be added to the model)
		//public TrackPerformanceView TrackPerformanceView { get; set; }
    }

TrackPerformanceView

[Table("TrackPerformanceView", Schema = "BoxOfficeDispo")]
    public class TrackPerformanceView
    {
        [Key]
        public Guid Id { get; set; }

        //Removing this relation here leads to a correct Model in the DataContext (Ef_Test.NotMapped.Auditorium will not be added to the model)
        [ForeignKey("Id")]
        public ScreenContentCountry ScreenContentCountry { get; set; }

        [NotMapped]
        public Ef_Test.NotMapped.Auditorium SharedAuditorium { get; set; }
    }

Auditorium (not added in the DbContext, only referenced with NotMapped attribute)

[Table("Auditoriums", Schema = "Shared")]
    public class Auditorium
    {
        [Key]
        public Guid Id { get; set; }
    }

As you might have seen in the comments of the code, there are ways to get the Auditorium entity type being ignored properly e.g. adding a navigation property for TrackPerformanceView in the ScreenContentCountry entity. Also not referencing the TrackPerformanceView from the ImportPerformance leads to a correct model with the Auditorium entity type being ignored.

In the example project the migration will anyway be generated correctly without the Auditorium type being added to the migration code.

What I’ve found out so far debugging ef core is that the RelationshipDiscoveryConvention.IsCandidateNavigationProperty returns true for the ​NotMapped Auditorium property in TrackPerformanceView

[NotMapped]
       ​public Ef_Test.NotMapped.Auditorium SharedAuditorium { get; set; }

this happens because sourceEntityTypeBuilder.IsIgnored(navigationName) returns false in this case.

RelationshipDiscoveryConvention.IsCandidateNavigationProperty

private static bool IsCandidateNavigationProperty(
      IConventionEntityTypeBuilder? sourceEntityTypeBuilder,
      string navigationName,
      MemberInfo memberInfo)
    {
      if (sourceEntityTypeBuilder != null && !sourceEntityTypeBuilder.IsIgnored(navigationName) && sourceEntityTypeBuilder.Metadata.FindProperty(navigationName) == null && sourceEntityTypeBuilder.Metadata.FindServiceProperty(navigationName) == null)
      {
        PropertyInfo propertyInfo1 = memberInfo as PropertyInfo;
        if ((object) propertyInfo1 == null || propertyInfo1.GetIndexParameters().Length == 0)
        {
          if (!sourceEntityTypeBuilder.Metadata.IsKeyless)
            return true;
          PropertyInfo propertyInfo2 = memberInfo as PropertyInfo;
          return ((object) propertyInfo2 != null ? propertyInfo2.PropertyType.TryGetSequenceType() : (Type) null) == (Type) null;
        }
      }
      return false;
    }

(After doing one of the steps said above this leads to the SharedAuditorium property being ignored properly, returning here false and for IsIgnored true).

Digging some deeper here leads to the TypeBase.FindDeclaredIgnoredConfigurationSource which is being called but has an empty dictionary of _ignoredMembers in the bugged case.

Let me now if you need some more information.

image

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:3
  • Comments:10 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
AndriySvyrydcommented, Jan 5, 2022

In 6.0 we had to change relationship discovery logic to enhance support for shared-type entity types, which introduced this issue where some [NotMapped] attributes are not being applied. Fixing this has a high chance of breaking something else, so it doesn’t meet the patch bar.

In 7.0 we’ll work on https://github.com/dotnet/efcore/issues/15898 which will allow us to use reference counting for entity types - a more accurate method to determine whether an entity type should be part of the model.

You can call EntityTypeBuilder.Ignore for now.

0reactions
tuxedogoldcommented, Jul 21, 2022

if you are using the workaround: modelBuilder.Entity<X>().Ignore(x => x.Field); route, make sure you get ALL of them on the entity(including entities further inheritted from).

Read more comments on GitHub >

github_iconTop Results From Across the Web

Creating a non mapped property in an entity ...
I want to create a custom property on one of my entities mapped from the database, however this property is not mapped to...
Read more >
The NotMapped Attribute
The NotMapped attribute is used to specify that an entity or property is not to be mapped to a table or column in...
Read more >
Entity Properties - EF Core
Each entity type in your model has a set of properties, which EF Core will read and write from the database. If you're...
Read more >
Fluent API - Configuring and Mapping Properties and Types
The following example shows how to specify that a property on a CLR type is not mapped to a column in the database....
Read more >
The property 'ItemBody.AdditionalData' could not be mapped ...
AdditionalData' could not be mapped because it is of type 'IDictionary', which is not a supported primitive type or a valid entity type....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found