SapientGuardian.EntityFrameworkCore.MySql
SapientGuardian.EntityFrameworkCore.MySql copied to clipboard
The entity type is part of a hierarchy, but with no discriminator property configured
I tried to migrate from using SQLite to MySQL for my project, and I keep getting this error: System.InvalidOperationException: The entity type 'Loan' is part of a hierarchy, but does not have a discriminator property configured.
My Loan model looks like this:
public class Loan
{
[Key]
public int LoanId { get; set; }
public int EquipmentId { get; set; }
public virtual Loaner Loaner { get; set; }
[Required]
public virtual Equipment Equipment { get; set; }
[Required]
public DateTime StartDate;
public DateTime EndDate;
public bool Applicable => this.EndDate < DateTime.Now;
}
Adding a Discriminator
property did not change anything.
I have a different model that inherits from the Loan
model:
public class Maintenance : Loan
{
public string Note { get; set; }
}
What could be causing this problem and how can I solve it?
I found a solution. Apparently, this provider doesn't automatically do registrations for derived classes, so you need to do them manually by overriding the #OnModelCreating()
method in your DbContext
-subclass.
Is there a particular reason as to why I need to do this? Shouldn't the provider do this automatically?
public class DokflytContext: DbContext
{
public DokflytContext(DbContextOptions<DokflytContext> options)
: base(options)
{
}
public DbSet<User> Users { get; set; }
public DbSet<Equipment> Equipments { get; set; }
public DbSet<Loan> Loans { get; set; }
public DbSet<Maintenance> Maintenances { get; set; }
public DbSet<Project> Projects { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Manually configure discriminators since the
// MySQL provider doesn't do it implicitly.
builder
.Entity<Loan>()
.HasDiscriminator<string>("Discriminator")
.HasValue<Loan>(nameof(Loan))
.HasValue<Maintenance>(nameof(Maintenance));
builder
.Entity<Loaner>()
.HasDiscriminator<string>("Discriminator")
.HasValue<Loaner>(nameof(Loaner))
.HasValue<User>(nameof(User))
.HasValue<Project>(nameof(Project));
}
}
I'm not sure. Do you know of other providers that don't behave this way?
The SQLite provider didn't behave this way. I haven't tested the other ones.
I took a quick search through the SQLite provider code, as well as through npgsql, and didn't see anything obvious around discriminators. What is the name of the column that SQLite creates as your discriminator column?
The name of the column is simply Discriminator
. It was created automatically when I added my initial migration.
This is the generated migration code for the Loan
model:
migrationBuilder.CreateTable(
name: "Loaner",
columns: table => new
{
LoanerId = table.Column<int>(nullable: false)
.Annotation("MySQL:AutoIncrement", true),
Discriminator = table.Column<string>(nullable: false),
PName = table.Column<string>(nullable: true),
Email = table.Column<string>(nullable: true),
FirstName = table.Column<string>(nullable: true),
LastName = table.Column<string>(nullable: true),
Password = table.Column<string>(nullable: true),
Role = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Loaner", x => x.LoanerId);
});
Discriminator = table.Column<string>(nullable: false)
was added automatically with the SQLite provider, but with the MySQL provider it wasn't.
Ok, that helped a lot in finding where this happens. I believe this behavior to be part of the RelationalConventionSetBuilder, which SqlServer, Sqlite, and Npgsql are all using, but we are not. It seems like something we should use, but I'm a little worried about it causing uenxpected behavior with current systems. I'll try wiring it up, and will bump this library by a minor version, rather than a revision.
@ts95 Can you give this version a try and see if it behaves as you expected? https://ci.appveyor.com/api/buildjobs/nycxtw9od923rciu/artifacts/artifacts%2FSapientGuardian.EntityFrameworkCore.MySql%2FSapientGuardian.EntityFrameworkCore.MySql.7.2.0.nupkg
Restore output
log : Restoring packages for dokflyt-utstyr/project.json...
log : Installing SapientGuardian.EntityFrameworkCore.MySql 7.2.0.
log : Restoring packages for tool 'Microsoft.AspNetCore.Razor.Tools' in dokflyt-utstyr/project.json...
log : Restoring packages for tool 'Microsoft.AspNetCore.Server.IISIntegration.Tools' in dokflyt-utstyr/project.json...
log : Restoring packages for tool 'Microsoft.DotNet.Watcher.Tools' in dokflyt-utstyr/project.json...
log : Restoring packages for tool 'Microsoft.EntityFrameworkCore.Tools.DotNet' in dokflyt-utstyr/project.json...
log : Writing lock file to disk. Path: dokflyt-utstyr/project.lock.json
log : dokflyt-utstyr/project.json
log : Restore completed in 8502ms.
Done: 0.
I still get the same error as before.
System.InvalidOperationException: The entity type 'Loan' is part of a hierarchy, but does not have a discriminator prope
rty configured.
at Microsoft.EntityFrameworkCore.Internal.ModelValidator.ShowError(String message)
at Microsoft.EntityFrameworkCore.Internal.RelationalModelValidator.ValidateDiscriminator(IEntityType entityType)
at Microsoft.EntityFrameworkCore.Internal.RelationalModelValidator.ValidateDiscriminatorValues(IEntityType rootEntity
Type) Closing connection to database 'DokflytUtstyr' on server '127.0.0.1'.
at Microsoft.EntityFrameworkCore.Internal.RelationalModelValidator.ValidateInheritanceMapping(IModel model)
...
You could reproduce this by creating a model that inherits from another one.
Base class
class Animal
{
[Key]
public int AnimalId { get; set; }
public int Weight { get; set; }
}
Subclass Dog
class Dog : Animal
{
public string Breed { get; set; }
}
Subclass Cat
class Cat : Animal
{
public bool IsHairless { get; set; }
}
If you create a migration for this it should generate just one table (called Animal
) with a Discriminator
column. The value of this column can either be Animal
, Dog
or Cat
, which would correspond with the type of the model.
Instead of generating it it simply throws the exception I posted above aka System.InvalidOperationException
@ts95 try abstract class Animal, like: https://docs.microsoft.com/en-us/aspnet/core/data/ef-mvc/inheritance