Reputation: 1074
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)
;
}
}
Upvotes: 2
Views: 3184
Reputation: 90
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"
}
Upvotes: 4