Custom Discriminator on base type = null: "but does not have a discriminator value configured"

.net-core c# entity-framework-core entity-framework-core-2.2

Question

I'd like to implement a TPH (Table Per Hierarchy) with a custom Discriminator. Here are the models:

public class Event
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime Start { get; set; }
}
public class Appointment : Event
{
    public TimeSpan Duration { get; set; }
}

My custom Discriminator should be the Duration column: If it's NULL than it must be an Event, otherwise an Appointment.

But I get this error on creating the migration step:

The entity type 'Event' is part of a hierarchy, but does not have a discriminator value configured.

What did I wrong? And how can I get the Discriminator up and running?


Here's the DbContext:

public class ApplicationDbContext : DbContext
{
    ...
    public DbSet<Event> Events { get; set; }
    public DbSet<Appointment> Appointments { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        ...
        modelBuilder.Entity<Event>()
            .HasDiscriminator<TimeSpan?>(nameof(Appointment.Duration))
            .HasValue(null)
            ;
    }
}
1
0
7/25/2019 1:13:47 PM

Accepted Answer

The error you get is originally because that the value of a Discriminator cannot be null. But Actually there is another problem that makes it not work.

Every entity type in TPH (Event and Appointment) must have a property as Discriminator.
If you don't specify any configuration for Discriminator, a property named Discriminator with type of string is used by default. This property stores name of the entity type and is used to examine what type a row maps to.

You can either leave the configuration of Discriminator (to the default behavior) or configure a custom one like this:

public class Event
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime Start { get; set; }
}
public class Appointment : Event
{
    public TimeSpan Duration { get; set; }
}

public class ApplicationDbContext : DbContext
{
    ...
    public DbSet<Event> Events { get; set; }
    public DbSet<Appointment> Appointments { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        ...
        modelBuilder.Entity<Event>()
            .HasDiscriminator<int>("discriminator")
            .HasValue<Event>(1)
            .HasValue<Appointment>(2);
    }
}

Note: if type of Discriminator is not string, then for each entity type in hierarchy, a discriminator value must be specified. (as shown in above code)

But If type of Discriminator is string, then it can be automatically filled with entity type name.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    ...
    modelBuilder.Entity<Event>()
        .HasDiscriminator<string>("discriminator")
        .HasValue("e"); // "e" is the value of discriminator for Event type. 
        // we don't need to specify another value for Appointment type. it defaults 
        // to "Appointment"
}
1
7/27/2019 1:03:06 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow