Efcore: Multiple properties with default implementation in an interface, applied to an abstract hierarchy, causes scaffolding to fail

Created on 11 Nov 2020  路  3Comments  路  Source: dotnet/efcore

Consider an interface which uses the default implementation feature on some temporary variables. Those temporary variables are marked with the [NotMapped] attribute. If _too many_ of those variables are used, and the interface is applied to an inheritance hierarchy which contains an _abstract_ ancestor, then the model is unable to scaffold. Please see the code example below:

```C#
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations.Schema;

namespace InterfaceOnDerived
{
class Program
{
static void Main(string[] args) { }
}
public class BloggingContext : DbContext
{
public DbSet BlogPosts { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(
            @"Server=(localdb)\mssqllocaldb;Database=Blogging;Integrated Security=True");
    }
}

public interface ITitle
{
    // commenting out one or more of these NotMapped properties fixes the problem
    [NotMapped] public string Temp1 => "abcd";
    [NotMapped] public string Temp2 => "abcd";
    [NotMapped] public string Temp3 => "abcd";
    [NotMapped] public string Temp4 => "abcd";
    [NotMapped] public string Temp5 => "abcd";

    public string Title { get; set; } // commenting out this property also fixes the problem
}

public abstract class Post : ITitle // making this non-abstract also fixes the problem
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public string Title { get; set; }

}
public class BlogPost : Post { }

}


PM> Add-Migration MyFirstMigration -v
Using project 'InterfaceOnDerived'.
Using startup project 'InterfaceOnDerived'.
Build started...
Build succeeded.
C:Program Filesdotnetdotnet.exe exec --depsfile "G:Google DriveTestProjectsInterfaceOnDerivedInterfaceOnDerivedbinDebugnet5.0InterfaceOnDerived.deps.json" --additionalprobingpath C:Usersvslee.nugetpackages --runtimeconfig "G:Google DriveTestProjectsInterfaceOnDerivedInterfaceOnDerivedbinDebugnet5.0InterfaceOnDerived.runtimeconfig.json" C:Usersvslee.nugetpackagesmicrosoft.entityframeworkcore.tools5.0.0toolsnetcoreapp2.0anyef.dll migrations add MyFirstMigration --json --verbose --no-color --prefix-output --assembly "G:Google DriveTestProjectsInterfaceOnDerivedInterfaceOnDerivedbinDebugnet5.0InterfaceOnDerived.dll" --startup-assembly "G:Google DriveTestProjectsInterfaceOnDerivedInterfaceOnDerivedbinDebugnet5.0InterfaceOnDerived.dll" --project-dir "G:Google DriveTestProjectsInterfaceOnDerivedInterfaceOnDerived\" --language C# --working-dir "G:Google DriveTestProjectsInterfaceOnDerived" --root-namespace InterfaceOnDerived
Using assembly 'InterfaceOnDerived'.
Using startup assembly 'InterfaceOnDerived'.
Using application base 'G:Google DriveTestProjectsInterfaceOnDerivedInterfaceOnDerivedbinDebugnet5.0'.
Using working directory 'G:Google DriveTestProjectsInterfaceOnDerivedInterfaceOnDerived'.
Using root namespace 'InterfaceOnDerived'.
Using project directory 'G:Google DriveTestProjectsInterfaceOnDerivedInterfaceOnDerived'.
Remaining arguments: .
Finding DbContext classes...
Finding IDesignTimeDbContextFactory implementations...
Finding application service provider in assembly 'InterfaceOnDerived'...
Finding Microsoft.Extensions.Hosting service provider...
No static method 'CreateHostBuilder(string[])' was found on class 'Program'.
No application service provider was found.
Finding DbContext classes in the project...
Found DbContext 'BloggingContext'.
Microsoft.EntityFrameworkCore.Design.OperationException: Unable to create an object of type 'BloggingContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
---> System.TypeLoadException: Method 'set_Title' in type 'InterfaceOnDerived.BlogPost' from assembly 'InterfaceOnDerived, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation.
at System.Signature.GetSignature(Void* pCorSig, Int32 cCorSig, RuntimeFieldHandleInternal fieldHandle, IRuntimeMethodInfo methodHandle, RuntimeType declaringType)
at System.Reflection.RuntimeMethodInfo.get_Signature()
at System.Reflection.RuntimeMethodInfo.FetchNonReturnParameters()
at System.Reflection.RuntimeMethodInfo.GetParametersNoCopy()
at System.Reflection.RuntimePropertyInfo.GetIndexParametersNoCopy()
at System.Reflection.RuntimePropertyInfo.GetIndexParameters()
at Microsoft.EntityFrameworkCore.Internal.DbSetFinder.<>c.b__2_0(PropertyInfo p)
at System.Linq.Enumerable.WhereArrayIterator1.ToArray() at System.Linq.Buffer1..ctor(IEnumerable1 source) at System.Linq.OrderedEnumerable1.GetEnumerator()+MoveNext()
at System.Linq.Enumerable.SelectIPartitionIterator2.LazyToArray() at System.Linq.Enumerable.SelectIPartitionIterator2.ToArray()
at System.Linq.Enumerable.ToArray[TSource](IEnumerable1 source) at Microsoft.EntityFrameworkCore.Internal.DbSetFinder.FindSetsNonCached(Type contextType) at System.Collections.Concurrent.ConcurrentDictionary2.GetOrAdd(TKey key, Func2 valueFactory) at Microsoft.EntityFrameworkCore.Internal.DbSetFinder.FindSets(Type contextType) at Microsoft.EntityFrameworkCore.Internal.DbSetInitializer.InitializeSets(DbContext context) at Microsoft.EntityFrameworkCore.DbContext..ctor(DbContextOptions options) at Microsoft.EntityFrameworkCore.DbContext..ctor() at InterfaceOnDerived.BloggingContext..ctor() --- End of stack trace from previous location --- at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.ConstructorMatcher.CreateInstance(IServiceProvider provider) at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance(IServiceProvider provider, Type instanceType, Object[] parameters) at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetServiceOrCreateInstance(IServiceProvider provider, Type type) at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.<>c__DisplayClass13_4.<FindContextTypes>b__13() --- End of inner exception stack trace --- at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.<>c__DisplayClass13_4.<FindContextTypes>b__13() at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(Func1 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.b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
Unable to create an object of type 'BloggingContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
```

EF Core version: 5.0 RTM
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 5.0 RTM
Operating system: Windows 10 Pro 20H2
IDE: Visual Studio 2019 16.8.0

closed-external customer-reported

Most helpful comment

Error is not related to EF Core at all. It happens without EF Core too.
Repro
```C#
using System;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Reflection;

namespace BugInReflection
{
class Program
{
static void Main(string[] args)
{
var p = typeof(Program).GetProperties().Select(e => e.GetIndexParameters()).ToList();
}

    public BlogPost BlogPost { get; set; }
}

public interface ITitle
{
    // commenting out one or more of these NotMapped properties fixes the problem
    [NotMapped] public string Temp1 => "abcd";
    [NotMapped] public string Temp2 => "abcd";
    [NotMapped] public string Temp3 => "abcd";
    [NotMapped] public string Temp4 => "abcd";
    [NotMapped] public string Temp5 => "abcd";

    public string Title { get; set; } // commenting out this property also fixes the problem
}

public abstract class Post : ITitle // making this non-abstract also fixes the problem
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public string Title { get; set; }

}
public class BlogPost : Post { }

}
```

All 3 comments

I also tried removing only the [NotMapped] attributes but leaving the default properties there, but that does not fix the problem.
Doing any of the three things in the code comments does, however.

Error is not related to EF Core at all. It happens without EF Core too.
Repro
```C#
using System;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Reflection;

namespace BugInReflection
{
class Program
{
static void Main(string[] args)
{
var p = typeof(Program).GetProperties().Select(e => e.GetIndexParameters()).ToList();
}

    public BlogPost BlogPost { get; set; }
}

public interface ITitle
{
    // commenting out one or more of these NotMapped properties fixes the problem
    [NotMapped] public string Temp1 => "abcd";
    [NotMapped] public string Temp2 => "abcd";
    [NotMapped] public string Temp3 => "abcd";
    [NotMapped] public string Temp4 => "abcd";
    [NotMapped] public string Temp5 => "abcd";

    public string Title { get; set; } // commenting out this property also fixes the problem
}

public abstract class Post : ITitle // making this non-abstract also fixes the problem
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public string Title { get; set; }

}
public class BlogPost : Post { }

}
```

Thank you for the quick response and debugging to figure out that the bug is external to EF Core. I should have dug deeper myself. I have now filed a bug in the appropriate repo https://github.com/dotnet/runtime/issues/44533.

Was this page helpful?
0 / 5 - 0 ratings