C
C#2d ago
Rese

EF Core with Pomelo MySQL TPC insists on creating abstract table - still not answered

Hello, I'm trying to do inheritance via TPC, but the abstract class is always created:
c#
public class CommonInvoice
{
public int Id { get; set; }

public DateTime CreatedAt { get; init; } = DateTime.Now;

public DateTime? DeletedAt { get; set; }

public required string Number { get; set; }

public required DateOnly DueDate { get; set; }

public required int CompanyId { get; set; }

public double DiscountPercentage { get; set; }

public double DiscountFixedValue { get; set; }

public virtual Company Company { get; set; } = default!;

public required int CustomerId { get; set; }

public virtual Customer Customer { get; set; } = default!;

public string? GeneratedFileName { get; set; }

public required int CreatedById { get; set; }

public virtual User CreatedBy { get; set; } = default!;

public required List<ItemizeItem> Items { get; set; }

public double TotalPrice
{
get
{
double total = 0;

foreach (var item in Items)
{
total += item.TotalPrice;
}
if (DiscountPercentage > 0)
{
total -= total * (DiscountPercentage / 100);
}
if (DiscountFixedValue > 0)
{
total -= DiscountFixedValue;
}
return Math.Max(total, 0);
}
}
}
public class Invoice : CommonInvoice
{
public required DateOnly DeliveryDate { get; set; }

public int? FromDepositInvoiceId { get; set; }

public virtual DepositInvoice? FromDepositInvoice { get; set; }
}
c#
public class CommonInvoice
{
public int Id { get; set; }

public DateTime CreatedAt { get; init; } = DateTime.Now;

public DateTime? DeletedAt { get; set; }

public required string Number { get; set; }

public required DateOnly DueDate { get; set; }

public required int CompanyId { get; set; }

public double DiscountPercentage { get; set; }

public double DiscountFixedValue { get; set; }

public virtual Company Company { get; set; } = default!;

public required int CustomerId { get; set; }

public virtual Customer Customer { get; set; } = default!;

public string? GeneratedFileName { get; set; }

public required int CreatedById { get; set; }

public virtual User CreatedBy { get; set; } = default!;

public required List<ItemizeItem> Items { get; set; }

public double TotalPrice
{
get
{
double total = 0;

foreach (var item in Items)
{
total += item.TotalPrice;
}
if (DiscountPercentage > 0)
{
total -= total * (DiscountPercentage / 100);
}
if (DiscountFixedValue > 0)
{
total -= DiscountFixedValue;
}
return Math.Max(total, 0);
}
}
}
public class Invoice : CommonInvoice
{
public required DateOnly DeliveryDate { get; set; }

public int? FromDepositInvoiceId { get; set; }

public virtual DepositInvoice? FromDepositInvoice { get; set; }
}
7 Replies
Rese
ReseOP2d ago
c#
public class DepositInvoice : CommonInvoice
{
public virtual List<Invoice> CreatedInvoices { get; set; } = [];
}
c#
public class DepositInvoice : CommonInvoice
{
public virtual List<Invoice> CreatedInvoices { get; set; } = [];
}
c#

public class DataContext(DbContextOptions options)
: IdentityDbContext<User, IdentityRole<int>, int>(options)
{
public DbSet<Invoice> Invoices { get; set; } = default!;
public DbSet<DepositInvoice> DepositInvoices { get; set; } = default!;

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

modelBuilder
.Entity<Company>()
.HasMany(x => x.Invoices)
.WithOne(x => x.Company)
.HasForeignKey(x => x.CompanyId);

modelBuilder
.Entity<Customer>()
.HasMany(x => x.Invoices)
.WithOne(x => x.Customer)
.HasForeignKey(x => x.CustomerId);

modelBuilder
.Entity<Company>()
.HasMany(x => x.DepositInvoices)
.WithOne(x => x.Company)
.HasForeignKey(x => x.CompanyId);

modelBuilder
.Entity<Customer>()
.HasMany(x => x.DepositInvoices)
.WithOne(x => x.Customer)
.HasForeignKey(x => x.CustomerId);

modelBuilder
.Entity<DepositInvoice>()
.HasMany(x => x.CreatedInvoices)
.WithOne(x => x.FromDepositInvoice)
.HasForeignKey(x => x.FromDepositInvoiceId);

var listItemizeItemConverter = new ValueConverter<List<ItemizeItem>, string>(
v =>
JsonSerializer.Serialize(v, typeof(List<ItemizeItem>), JsonHelper.INDENTED_OPTIONS),
v =>
JsonSerializer.Deserialize<List<ItemizeItem>>(v, JsonHelper.INDENTED_OPTIONS)
?? new List<ItemizeItem>()
);

modelBuilder
.Entity<CommonInvoice>()
.Property(x => x.Items)
.HasConversion(listItemizeItemConverter);

modelBuilder.Entity<CommonInvoice>().UseTpcMappingStrategy();
}
}
c#

public class DataContext(DbContextOptions options)
: IdentityDbContext<User, IdentityRole<int>, int>(options)
{
public DbSet<Invoice> Invoices { get; set; } = default!;
public DbSet<DepositInvoice> DepositInvoices { get; set; } = default!;

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

modelBuilder
.Entity<Company>()
.HasMany(x => x.Invoices)
.WithOne(x => x.Company)
.HasForeignKey(x => x.CompanyId);

modelBuilder
.Entity<Customer>()
.HasMany(x => x.Invoices)
.WithOne(x => x.Customer)
.HasForeignKey(x => x.CustomerId);

modelBuilder
.Entity<Company>()
.HasMany(x => x.DepositInvoices)
.WithOne(x => x.Company)
.HasForeignKey(x => x.CompanyId);

modelBuilder
.Entity<Customer>()
.HasMany(x => x.DepositInvoices)
.WithOne(x => x.Customer)
.HasForeignKey(x => x.CustomerId);

modelBuilder
.Entity<DepositInvoice>()
.HasMany(x => x.CreatedInvoices)
.WithOne(x => x.FromDepositInvoice)
.HasForeignKey(x => x.FromDepositInvoiceId);

var listItemizeItemConverter = new ValueConverter<List<ItemizeItem>, string>(
v =>
JsonSerializer.Serialize(v, typeof(List<ItemizeItem>), JsonHelper.INDENTED_OPTIONS),
v =>
JsonSerializer.Deserialize<List<ItemizeItem>>(v, JsonHelper.INDENTED_OPTIONS)
?? new List<ItemizeItem>()
);

modelBuilder
.Entity<CommonInvoice>()
.Property(x => x.Items)
.HasConversion(listItemizeItemConverter);

modelBuilder.Entity<CommonInvoice>().UseTpcMappingStrategy();
}
}
Rese
ReseOP2d ago
Resulting migration
Rese
ReseOP2d ago
I've redacted as much as I thought was not needed to keep this as short as possible - changing title since people could disregard due to 5 messages in this thread, even though they're all initial post
Unknown User
Unknown User2d ago
Message Not Public
Sign In & Join Server To View
Rese
ReseOP2d ago
so as far as the actual issue goes, you're saying it's probably caused by mysql (or the driver/provider to be precise)? ye I'm using pomelo I'm just dumbfounded because I've used TpcMapping the same way in another project and this issue didn't occur there
Unknown User
Unknown User2d ago
Message Not Public
Sign In & Join Server To View
Rese
ReseOP2d ago
ah I see I went with mysql since it's relational, lightweight and has phpMyAdmin and it's what I know not against switching to something else, but would be nice to know if I ducked something up lol

Did you find this page helpful?