-2

I get an error when on the OnModelCreating to seed my database. It says that I have a null reference exception. I can't figure out why. Please see my Classes:

public class TicketHeader
{
    [Key]
    public int Id { get; set; }
    [Column(TypeName = "datetime")]
    [Required (ErrorMessage = "Ticket date is required.")]
    public DateTime DateOpened { get; set; }
    [Column(TypeName = "datetime")]
    public DateTime? DateClosed { get; set; }
    [Column(TypeName = "nvarchar(200)")]
    [Required(ErrorMessage = "Add a description to the ticket.")]
    [StringLength(50, MinimumLength = 2, ErrorMessage = "Description must be a minimum of 2 and maximum of 200 characters.")]
    public string TicketDescription { get; set; }
    [Column(TypeName = "nvarchar(50)")]
    [Required(ErrorMessage = "Forwarding email address is required.")]
    [EmailAddress (ErrorMessage = "Email is not in a valid format.")]
    public string TicketRequesterEmail { get; set; }
    [Column(TypeName = "nvarchar(100)")]
    public string AttachmentPath { get; set; }
    [Column(TypeName = "nvarchar(100)")]
    public string TicketGuid { get; set; } = Guid.NewGuid().ToString();
    [Column(TypeName = "nvarchar(20)")]
    [Required(ErrorMessage = "Ticket status is required.")]
    public Status TicketStatus { get; set; } = Status.New;
    public int DepartmentId{ get; set; }

    public ICollection<TicketDetail> TicketDetails { get; set; }
}
    
public class TicketDetail
{
    [Key]
    public int Id { get; set; }
    public DateTime? DetailDate { get; set; } = DateTime.Now;
    [Column(TypeName = "nvarchar(300)")]
    public string Description { get; set; }
}

And this is on my AppDbContext

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }

    public DbSet<TicketHeader> TicketHeaders { get; set; }
    public DbSet<Department> Departments { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Department>().HasData(
                new Department { DepartmentId = 1, DepartmentName = "DevOps" }
            );
        modelBuilder.Entity<Department>().HasData(
                new Department { DepartmentId = 2, DepartmentName = "IS" }
            );
        modelBuilder.Entity<Department>().HasData(
                new Department { DepartmentId = 3, DepartmentName = "SEMM" }
            );
        modelBuilder.Entity<Department>().HasData(
                new Department { DepartmentId = 4, DepartmentName = "Networking" }
            );
        modelBuilder.Entity<Department>().HasData(
                new Department { DepartmentId = 5, DepartmentName = "Maintenance" }
            );

        modelBuilder.Entity<TicketHeader>().HasData(new TicketHeader
        {
            AttachmentPath = "attachments/ticketImage.png",
            DateOpened = new DateTime(2021, 10, 5),
            DepartmentId = 1,
            Id = 1,
            TicketDescription = "This is a description for ticket 1",
            TicketRequesterEmail = "test@emai.com",
            TicketStatus = Status.New,
            TicketDetails = {
                    new TicketDetail
                    {
                        Description = "Description for ticket 1"
                    }
                }
        });

        modelBuilder.Entity<TicketHeader>().HasData(new TicketHeader
        {
            AttachmentPath = "attachments/ticketImage.png",
            DateOpened = new DateTime(2021, 1, 4),
            DepartmentId = 2,
            Id = 2,
            TicketDescription = "This is a description for ticket 3",
            TicketRequesterEmail = "test@emai.com",
            TicketStatus = Status.New,
            TicketDetails = {
                        new TicketDetail
                        {
                            Description = "Description for ticket 3"
                        }
           }
        });

        modelBuilder.Entity<TicketHeader>().HasData(new TicketHeader
        {
            AttachmentPath = "attachments/ticketImage.png",
            DateOpened = new DateTime(2021, 2, 5),
            DepartmentId = 3,
            Id = 3,
            TicketDescription = "This is a description for ticket 4",
            TicketRequesterEmail = "test@emai.com",
            TicketStatus = Status.New,
            TicketDetails = {
                        new TicketDetail
                        {
                            Description = "Description for ticket 4"
                        }
              }
        });

        modelBuilder.Entity<TicketHeader>().HasData(new TicketHeader
        {
            AttachmentPath = "attachments/ticketImage.png",
            DateOpened = new DateTime(2021, 3, 5),
            DepartmentId = 4,
            Id = 4,
            TicketDescription = "This is a description for ticket 5",
            TicketRequesterEmail = "test@emai.com",
            TicketStatus = Status.New,
            TicketDetails = {
                        new TicketDetail
                        {
                            Description = "Description for ticket 5"
                        }
              }
        });

        modelBuilder.Entity<TicketHeader>().HasData(new TicketHeader
        {
            AttachmentPath = "attachments/ticketImage.png",
            DateOpened = new DateTime(2021, 4, 5),
            DepartmentId = 1,
            Id = 5,
            TicketDescription = "This is a description for ticket 1",
            TicketRequesterEmail = "test@emai.com",
            TicketStatus = Status.New,
            TicketDetails = {
                        new TicketDetail
                        {
                            Description = "Description for ticket 1"
                        }
              }
        });
    }
}

In my startup

public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<AppDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

            services.AddScoped<IDepartmentRepository, DepartmentRepository>();
            services.AddScoped<ITicketRepository, TicketRepository>();

            services.AddControllers();
        }

And this is what I get when I run the migration

PM> dotnet ef migrations add InitialCreate --project .\HelpDeskApi\HelpDeskApi.csproj Build started... Build succeeded. System.NullReferenceException: Object reference not set to an instance of an object. at HelpDeskApi.Models.AppDbContext.OnModelCreating(ModelBuilder modelBuilder) in D:\Projects\Autosweep\HelpDesk\API\HelpDeskApi\Models\AppDbContext.cs:line 32 at Microsoft.EntityFrameworkCore.Infrastructure.ModelCustomizer.Customize(ModelBuilder modelBuilder, DbContext context) at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder) at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder) at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel() at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model() at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.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.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](IInfrastructure1 accessor) 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) at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType) at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0() at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_01.b__0() at ......

What am I doing wrong?

halfer
  • 19,824
  • 17
  • 99
  • 186
Ibanez1408
  • 4,550
  • 10
  • 59
  • 110
  • Does it help if you put something like this into your AppDbContext class with your connection string details?. protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { if (!optionsBuilder.IsConfigured) { optionsBuilder.UseSqlServer("Server=MyServer;Database=MyDb;Trusted_Connection=True;"); } } – fuzzy_logic Jun 24 '21 at 02:53
  • If I remove the seeding of TicketHeader, I run it fine. I think the issue is in the seeding of the TicketHeader. – Ibanez1408 Jun 24 '21 at 03:44
  • Which version of .NET Core are you using? – fuzzy_logic Jun 24 '21 at 04:31
  • What happened when you added the snippet I originally added, same error? Also check the EF Core seeding sample on [GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Modeling/DataSeeding) – fuzzy_logic Jun 24 '21 at 04:42
  • Nevermind previous comments, managed to get it working as per answer below.. – fuzzy_logic Jun 24 '21 at 06:35
  • You have to seed `TicketDetails` in their own `HasData` statements. – Gert Arnold Jun 24 '21 at 07:20

2 Answers2

1

Have a read of this Julie Lerman MSDN article, I was able to get working in EF Core 3.1.6 as per below.

Note: I did need to udpate your entity classes slightly, also included.

Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<AppDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
}

AppDbContext.cs

using System;
using Microsoft.EntityFrameworkCore;

namespace EfCoreTest
{
    public class AppDbContext : DbContext
    {
        public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }

        public DbSet<TicketDetail> TicketDetails { get; set; }
        public DbSet<TicketHeader> TicketHeaders { get; set; }
        public DbSet<Department> Departments { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Department>(d =>
            {
                d.HasData(new Department { DepartmentId = 1, DepartmentName = "DevOps"},
                    new Department { DepartmentId = 2, DepartmentName = "IS"});
            });

            modelBuilder.Entity<TicketHeader>(th =>
            {
                th.HasData(new TicketHeader
                {
                    Id = 1,
                    AttachmentPath = "attachments/ticketImage.png",
                    DateOpened = new DateTime(2021, 10, 5),
                    DepartmentId = 1,
                    TicketDescription = "Description for ticket 1",
                    TicketRequesterEmail = "test@emai.com"
                },
                new TicketHeader
                {
                    Id = 2,
                    AttachmentPath = "attachments/ticketImage.png",
                    DateOpened = new DateTime(2021, 1, 4),
                    DepartmentId = 2,
                    TicketDescription = "Description for ticket 2",
                    TicketRequesterEmail = "test@emai.com"
                });
            });

            modelBuilder.Entity<TicketDetail>(td =>
            {
                td.HasData(new TicketDetail {Id = 1, TicketHeaderId = 1, Description = "Detail 1 for ticket 1"},
                    new TicketDetail {Id =2, TicketHeaderId = 1, Description = "Detail 2 for ticket 1" },
                    new TicketDetail { Id = 3, TicketHeaderId = 2, Description = "Detail 1 for ticket 2" });
            });
        }
    }
}

Classes:

public class Department
{
    [Key]
    public int DepartmentId { get; set; }
    [Column(TypeName = "nvarchar(300)")]
    public string DepartmentName { get; set; }
}

public class TicketHeader
{
    [Key]
    public int Id { get; set; }
    [Column(TypeName = "datetime")]
    [Required(ErrorMessage = "Ticket date is required.")]
    public DateTime DateOpened { get; set; }
    [Column(TypeName = "datetime")]
    public DateTime? DateClosed { get; set; }
    [Column(TypeName = "nvarchar(200)")]
    [Required(ErrorMessage = "Add a description to the ticket.")]
    [StringLength(50, MinimumLength = 2, ErrorMessage = "Description must be a minimum of 2 and maximum of 200 characters.")]
    public string TicketDescription { get; set; }
    [Column(TypeName = "nvarchar(50)")]
    [Required(ErrorMessage = "Forwarding email address is required.")]
    [EmailAddress(ErrorMessage = "Email is not in a valid format.")]
    public string TicketRequesterEmail { get; set; }
    [Column(TypeName = "nvarchar(100)")]
    public string AttachmentPath { get; set; }
    [Column(TypeName = "nvarchar(100)")]
    public string TicketGuid { get; set; } = Guid.NewGuid().ToString();
    public int DepartmentId { get; set; }
    public Department Department { get; set; }

    public ICollection<TicketDetail> TicketDetails { get; set; }
}

public class TicketDetail
{
    [Key]
    public int Id { get; set; }
    public DateTime? DetailDate { get; set; } = DateTime.Now;
    [Column(TypeName = "nvarchar(300)")]
    public string Description { get; set; }

    public int TicketHeaderId { get; set; }
    public TicketHeader TicketHeader { get; set; }
}

In the '...InititialCreate.cs' file output from the AddMigration command you should now have Insert Data for Departments, TicketHeaders and TicketDetails.

fuzzy_logic
  • 896
  • 11
  • 14
  • 1
    Then what about "you can’t build graphs as parameters of HasData"? – Gert Arnold Jun 24 '21 at 07:19
  • I did test the code I included.. Anonomous types maybe.. – fuzzy_logic Jun 24 '21 at 07:24
  • Well, I don't think you have any `TicketDetails` in the database. Because of the anon. types the property `TicketDetails` is simply ignored. That's why it's not a good idea to seed with anon. types if you can (and should) use the entity classes. – Gert Arnold Jun 24 '21 at 07:52
  • 1
    Thanks @GertArnold, you're correct. I've udapted and tested the above, including 'ef database update' which now looks correct in my test db. – fuzzy_logic Jun 24 '21 at 23:47
0

Based on the exception details this seems like due to dependency injection.

You should register DBContext in your startup.cs file as a service. Check ConfigureServices method in your startup.cs file.

You should have it registered like below.

            services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
Darshani Jayasekara
  • 561
  • 1
  • 4
  • 14