Efcore: Question: 1..N relation on EF 2.1: "reached the recursion limit."

Created on 10 Jun 2018  Â·  6Comments  Â·  Source: dotnet/efcore

I trying to initialize the first migration with dotnet ef migrations add EmailMigration but I have the following error:

The convention invocations have reached the recursion limit. This is likely an issue in EF Core, please report it

Stack trace:

System.InvalidOperationException: The convention invocations have reached the recursion limit. This is likely an issue in EF Core, please report it.
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ConventionBatch.Run()
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ConventionBatch.Dispose()
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.RelationshipDiscoveryConvention.DiscoverRelationships(InternalEntityTypeBuilder entityTypeBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.RelationshipDiscoveryConvention.Apply(InternalEntityTypeBuilder entityTypeBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnEntityTypeAdded(InternalEntityTypeBuilder entityTypeBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnEntityTypeAdded(InternalEntityTypeBuilder entityTypeBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Internal.Model.AddEntityType(EntityType entityType)
   at Microsoft.EntityFrameworkCore.Metadata.Internal.Model.AddEntityType(Type type, ConfigurationSource configurationSource)
   at Microsoft.EntityFrameworkCore.Metadata.Internal.InternalModelBuilder.Entity(TypeIdentity& type, ConfigurationSource configurationSource, Boolean throwOnQuery)
   at Microsoft.EntityFrameworkCore.Metadata.Internal.InternalModelBuilder.Entity(Type type, ConfigurationSource configurationSource, Boolean throwOnQuery)
   at Microsoft.EntityFrameworkCore.ModelBuilder.Entity(Type type)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelCustomizer.FindSets(ModelBuilder modelBuilder, DbContext context)
   at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelCustomizer.FindSets(ModelBuilder modelBuilder, DbContext context)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelCustomizer.Customize(ModelBuilder modelBuilder, DbContext context)
   at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelCustomizer.Customize(ModelBuilder modelBuilder, DbContext context)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder, IModelValidator validator)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.<>c__DisplayClass5_0.<GetModel>b__1()
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
   at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
   at System.Lazy`1.CreateValue()
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder, IModelValidator validator)
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel()
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
   at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__7_1(IServiceProvider p)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.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_InternalServiceProvider()
   at Microsoft.EntityFrameworkCore.DbContext.Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure<System.IServiceProvider>.get_Instance()
   at Microsoft.EntityFrameworkCore.Internal.InternalAccessorExtensions.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)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_1.<.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)

Steps to reproduce

I create a new template for webapi with dotnet new webapi, and added my models and the bugged context:

```c#
public class UserModel
{
public long Id { get; set; }

public string Password { get; set; }

public bool FirstLogin { get; set; }

public DateTime LastLoginAt { get; set; }

public DateTime CreatedAt { get; set; }

public string Roles { get; set; }

[ForeignKey("Emails")]
public long EmailModelId { get; set; }
public ICollection<EmailModel> Emails{ get; set; }

}

public class EmailModel
{
public long Id { get; set; }

public string MailAddress { get; set; }

public bool Main { get; set; }

public bool ReceiveNews { get; set; } = true;

public bool Confirmed { get; set; } = false;

[ForeignKey("Owner")]
public long UserModelId { get; set; }
public UserModel Owner { get; set; }

}

public class UserContext : DbContext, IDesignTimeDbContextFactory
{
public DbSet Emails { get; set; }
public DbSet Users { get; set; }

public UserContext(DbContextOptions options) : base(options)
{

}

public UserContext()
{

}

public UserContext CreateDbContext(string[] args)
{
    return new UserContext(
        new DbContextOptionsBuilder<UserContext>().UseSqlite(Startup.Configuration["ConnectionString"])
            .Options);
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<UserModel>()
        .HasMany(e => e.Mails)
        .WithOne(u => u.Owner)
        .HasForeignKey(e => e.Id);

    modelBuilder.Entity<EmailModel>()
        .HasOne(u => u.Owner);
}

}
```

Further technical details

EF Core version: 2.1.0
Database Provider: Microsoft.EntityFrameworkCore.Sqlite
Operating system: Windows 10
IDE: JetBrains Rider 2018.2

closed-question customer-reported

Most helpful comment

@JonasUliana It looks like there are multiple issues with the code. For example::

  • The same navigation properties are used to define multiple different relationships
  • The FK is mapped to the same property as the PK for a one-to-many relationship.
  • The ForeignKey attribute suggests that EmailModelId should be used as an FK, but no property of that name exists on the dependent end.

Rather than trying to figure out the intent here, can you describe hat tables and foreign keys you expect from the mapping of these types?

All 6 comments

@JonasUliana It looks like there are multiple issues with the code. For example::

  • The same navigation properties are used to define multiple different relationships
  • The FK is mapped to the same property as the PK for a one-to-many relationship.
  • The ForeignKey attribute suggests that EmailModelId should be used as an FK, but no property of that name exists on the dependent end.

Rather than trying to figure out the intent here, can you describe hat tables and foreign keys you expect from the mapping of these types?

@ajcvickers, I trying to create one to many relationship in User model to Email model with the following logic:

  • A Users can have many Emails;
  • One Email can have only one User;

I am trying to do that with annotation and/or fluent API, but no success, the issue is my implementation right?

@JonasUliana Are you intending to use a specific property/column for the foreign key? Or do you not care as long as it works?

@ajcvickers I prefer the best implementation, but a working behaviour is enough for studying purposes.

It sounds like you are trying to do a simple a user has multiple emails 1- many relationship and the emails must be unique in the system
```c#
context:

public class UserModel
{
//….
[ForeignKey("Emails")]
public long EmailModelId { get; set; } //I think all you need to do is remove this and the relationship will be found by convention
public ICollection Emails{ get; set; }
}

```

@JonasUliana Thought I posted this yesterday, but I must have not pressed the button or something. Assuming that UserModelId should be the FK and EmailModelId is erroneous, then using entity types like so:

```C#
public class UserModel
{
public long Id { get; set; }
public string Password { get; set; }
public bool FirstLogin { get; set; }
public DateTime LastLoginAt { get; set; }
public DateTime CreatedAt { get; set; }
public string Roles { get; set; }
public ICollection Emails { get; set; }
}

public class EmailModel
{
public long Id { get; set; }
public string MailAddress { get; set; }
public bool Main { get; set; }
public bool ReceiveNews { get; set; } = true;
public bool Confirmed { get; set; } = false;
public long UserModelId { get; set; }
public UserModel Owner { get; set; }
}

will result in the relationship you described being created by convention. This means that no additional configuration is needed. However, if you would like to explicitly specify the relationship, then the following code will do that:

```C#
modelBuilder
    .Entity<UserModel>()
    .HasMany(e => e.Emails)
    .WithOne(e => e.Owner)
    .HasForeignKey(e => e.UserModelId);
Was this page helpful?
0 / 5 - 0 ratings