1

Starting out with EF Core, I'm trying to use an abstract class. I understand that I can't instantiate an abstract class and have a part of code missing but cannot find how to solve it.

The code is as follows:

using System;
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using Microsoft.Extensions.Logging;

namespace ProjectTest1 
{
    public abstract class User 
    {
        [Key]
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Password { get; set; }
        public string Email { get; set; }
        public bool IsAdmin { get; set; }
    }

    public class Student : User 
    {
        public string Number { get; set; }
    }

    public class Teacher : User 
    {
        public int Salary { get; set; }
    }

    public class Model : DbContext 
    {
        public static readonly ILoggerFactory _loggerFactory = LoggerFactory.Create(builder => {
            builder.AddConsole();
        });

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
            base.OnConfiguring(optionsBuilder);
            optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=project")
                .EnableSensitiveDataLogging()
                .UseLoggerFactory(_loggerFactory);
        }

        public DbSet<User> Users { get; set; }
    }

    class Program 
    {
        static void Main(string[] args) 
        {
            using var model = new Model();
            model.Database.EnsureCreated();

            model.Users.RemoveRange(model.Users);
            model.SaveChanges();

            var guillaume = new Student() 
            {
                FirstName = "guillaume", 
                LastName = "b", 
                Password = "azerty",
                Email = "[email protected]", 
                IsAdmin = true,
                Number = "150200"
            };

            var donald = new Teacher() 
            {
                FirstName = "donald", 
                LastName = "c", 
                Password = "azerty",
                Email = "[email protected]", 
                IsAdmin = false, 
                Salary = 35000
            };

            model.Users.AddRange(new User[] { guillaume, donald });
            model.SaveChanges();
        }
    }
}

The execution of the code produce error:

System.InvalidOperationException
HResult=0x80131509

Message=The corresponding CLR type for entity type 'User' cannot be instantiated, and there is no derived entity type in the model that corresponds to a concrete CLR type.

Source=Microsoft.EntityFrameworkCore

StackTrace:

at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.ValidateClrInheritance(IModel model, IEntityType entityType, HashSet1 validEntityTypes) at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.ValidateClrInheritance(IModel model, IDiagnosticsLogger1 logger) at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.Validate(IModel model, IDiagnosticsLogger1 logger) at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.Validate(IModel model, IDiagnosticsLogger1 logger) at Microsoft.EntityFrameworkCore.SqlServer.Internal.SqlServerModelValidator.Validate(IModel model, IDiagnosticsLogger1 logger) at Microsoft.EntityFrameworkCore.Metadata.Conventions.ValidatingConvention.ProcessModelFinalized(IModel model) at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelFinalized(IModel model) at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnModelFinalized(IModel model) at Microsoft.EntityFrameworkCore.Metadata.Internal.Model.FinalizeModel() at Microsoft.EntityFrameworkCore.ModelBuilder.FinalizeModel() at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder, ModelDependencies modelDependencies) at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder, ModelDependencies modelDependencies) at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel() at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model() at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__7_3(IServiceProvider p) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.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 singletonCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSite(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.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 singletonCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSite(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope) 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.Infrastructure.Internal.InfrastructureExtensions.GetService[TService](IInfrastructure1 accessor) at Microsoft.EntityFrameworkCore.Infrastructure.AccessorExtensions.GetService[TService](IInfrastructure`1 accessor) at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.get_Dependencies() at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.EnsureCreated() at ProjectTest1.Program.Main(String[] args) in C:\Users\yamab\Desktop\ProjectTest1\ProjectTest1\Program.cs:line 48

Reading this tutorial I think I should do something like this

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<User>()
                .Map<Studentt>(m => m.Requires("User").HasValue("S"))
                .Map<Teacher>(m => m.Requires("Usre").HasValue("T"));
}

Not sure this is what I should do nor how to do it exactly?

8
  • 1
    If you want a "User" Entity, it cannot be abstract. Commented Apr 13, 2021 at 13:29
  • @Fildor Thanks for your reply. why in the tutorial I mentioned it seem to be done or how then should I do to use student and teacher extending user? Commented Apr 13, 2021 at 13:37
  • User can only be abstract if it itself is not an Entity. So, if in your tutorial, some class is abstract, then you are doing something differently than in the tutorial. Commented Apr 13, 2021 at 13:40
  • 1
    Aw, wait a second. ... "Table per Hierarchy" ... that article is from 2010, so probably refers to Entity Framework, not EF Core. Are you using EF Core? AFAIK, there are some of these concepts, that are not (yet) supported in EF Core as opposed to Entity Framework. Commented Apr 13, 2021 at 13:43
  • 1
    @Fildor I will read those resources, thank you for your assistance Commented Apr 13, 2021 at 13:55

1 Answer 1

5

Thank you to @Fildor for the assistance and pointing me to Entity type hierarchy mapping

The solution was to add

public DbSet<Student> Students { get; set; }
public DbSet<Teacher> Teachers { get; set; }

Complet code:

using System;
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using Microsoft.Extensions.Logging;

namespace ProjectTest1 {

    public abstract class User {
        [Key]
        public string FirstName { get; set; }

        public string LastName { get; set; }

        public string Password { get; set; }

        public string Email { get; set; }

        public bool IsAdmin { get; set; }

    }

    public class Student : User {
        public string Number { get; set; }
    }

    public class Teacher : User {
        public int Salary { get; set; }
    }

    public class Model : DbContext {

        public static readonly ILoggerFactory _loggerFactory = LoggerFactory.Create(builder => {
            builder.AddConsole();
        });
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
            base.OnConfiguring(optionsBuilder);
            optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=project")
                .EnableSensitiveDataLogging()
                .UseLoggerFactory(_loggerFactory);
        }

        public DbSet<User> Users { get; set; }
        public DbSet<Student> Students { get; set; }
        public DbSet<Teacher> Teachers { get; set; }
    }

    class Program {
        static void Main(string[] args) {
            using var model = new Model();
            model.Database.EnsureCreated();

            model.Users.RemoveRange(model.Users);
            model.SaveChanges();

            var guillaume = new Student() {
                FirstName = "guillaume", LastName = "b", Password = "azerty",
                Email = "[email protected]", IsAdmin = true , Number = "150200"
            };
            var donald = new Teacher() {
                FirstName = "donald", LastName = "c", Password = "azerty",
                Email = "[email protected]", IsAdmin = false, Salary = 35000
            };

            model.Users.AddRange(new User[] { guillaume, donald });
            model.SaveChanges();

        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.