admin管理员组文章数量:1122846
I typically use the following interfaces for EF Core entities (.NET 9, EF Core 9):
public interface IEntity
where TEntity: class, new()
{
// Identity column.
public long Id { get; set; }
public bool IsAuditable { get; set; }
public DateTime DateTimeCreated { get; set; }
public DateTime? DateTimeModified { get; set; }
}
public interface IEntity<TEntity>:
IEntity
where TEntity: class, IEntity, IEntity<TEntity>, new()
{ }
I am now considering using concrete base classes for all entities.
Consider the following hierarchy:
// Acts as a based class for all entities in the DbContext.
public class EntityBase<TEntity>:
IEntity<TEntity>
where TEntity : class, IEntity, IEntity<TEntity>, new()
{
// Identity column.
public long Id { get; set; }
public bool IsAuditable { get; set; }
public DateTime DateTimeCreated { get; set; }
public DateTime? DateTimeModified { get; set; }
}
public class DocumentBase : EntityBase<DocumentBase>
{
public string Name { get; set; }
}
public class ElementBase : EntityBase<ElementBase>
{
public string Name { get; set; }
}
// Should represent a database table with all properties
// from the base class but without a discriminator column.
public class Document : DocumentBase
{
public virtual ICollection<Element> Elements { get; set; } = [];
}
// Should represent a database table with all properties
// from the base class but without a discriminator column.
public class Element : ElementBase
{
public long DocumentId { get; set; }
public virtual Document Document { get; set; }
}
public class ApplicationDbContext : DbContext
{
public DbSet<Document> Documents { get; set; }
public DbSet<Element> Elements { get; set; }
}
A couple of things to notice:
- Neither
DocumentBase
, norElementBase
should be required to be abstract (we should have the option to mark them as abstract if needed) - The
DbContext
should know nothing about these base classes except their properties (as if they were declared in the concrete classes) - The only commonality between various entities will converge at
ConcreteEntity > ConcreteEntityBase > EntityBase
. No other paths need to be considered
The resulting tables should have the following declarations WITHOUT a discriminator column (no TPH, TPT):
Tables:
Document
(Id, IsAuditable, DateTimeCreated, DateTimeModified, Name, Elements)Element
(Id, IsAuditable, DateTimeCreated, DateTimeModified, Name, Document, DocumentId)
The best resource I found was this blog discussing Table per Concrete Type (TPC)
, but it is over a decade old, while I am trying to make sense of EF Core 9.
Please note that this question is not about design choices or whether my approach aligns with best practices. I simply want to know whether this can be achieved with EF9 and, if so, what configuration is needed.
I typically use the following interfaces for EF Core entities (.NET 9, EF Core 9):
public interface IEntity
where TEntity: class, new()
{
// Identity column.
public long Id { get; set; }
public bool IsAuditable { get; set; }
public DateTime DateTimeCreated { get; set; }
public DateTime? DateTimeModified { get; set; }
}
public interface IEntity<TEntity>:
IEntity
where TEntity: class, IEntity, IEntity<TEntity>, new()
{ }
I am now considering using concrete base classes for all entities.
Consider the following hierarchy:
// Acts as a based class for all entities in the DbContext.
public class EntityBase<TEntity>:
IEntity<TEntity>
where TEntity : class, IEntity, IEntity<TEntity>, new()
{
// Identity column.
public long Id { get; set; }
public bool IsAuditable { get; set; }
public DateTime DateTimeCreated { get; set; }
public DateTime? DateTimeModified { get; set; }
}
public class DocumentBase : EntityBase<DocumentBase>
{
public string Name { get; set; }
}
public class ElementBase : EntityBase<ElementBase>
{
public string Name { get; set; }
}
// Should represent a database table with all properties
// from the base class but without a discriminator column.
public class Document : DocumentBase
{
public virtual ICollection<Element> Elements { get; set; } = [];
}
// Should represent a database table with all properties
// from the base class but without a discriminator column.
public class Element : ElementBase
{
public long DocumentId { get; set; }
public virtual Document Document { get; set; }
}
public class ApplicationDbContext : DbContext
{
public DbSet<Document> Documents { get; set; }
public DbSet<Element> Elements { get; set; }
}
A couple of things to notice:
- Neither
DocumentBase
, norElementBase
should be required to be abstract (we should have the option to mark them as abstract if needed) - The
DbContext
should know nothing about these base classes except their properties (as if they were declared in the concrete classes) - The only commonality between various entities will converge at
ConcreteEntity > ConcreteEntityBase > EntityBase
. No other paths need to be considered
The resulting tables should have the following declarations WITHOUT a discriminator column (no TPH, TPT):
Tables:
Document
(Id, IsAuditable, DateTimeCreated, DateTimeModified, Name, Elements)Element
(Id, IsAuditable, DateTimeCreated, DateTimeModified, Name, Document, DocumentId)
The best resource I found was this blog discussing Table per Concrete Type (TPC)
, but it is over a decade old, while I am trying to make sense of EF Core 9.
Please note that this question is not about design choices or whether my approach aligns with best practices. I simply want to know whether this can be achieved with EF9 and, if so, what configuration is needed.
Share Improve this question edited Dec 3, 2024 at 1:27 Zhi Lv 21.2k1 gold badge26 silver badges36 bronze badges asked Nov 22, 2024 at 1:56 Raheel KhanRaheel Khan 14.8k14 gold badges86 silver badges170 bronze badges 3 |1 Answer
Reset to default 3You shouldn't need to define any inheritance configuration for EF to do what you expect, so long as you don't have any DbSet
or entity configuration declared for the base class. Any explicit configuration you might need (data types, column naming, etc.) simply do through the end sub-classes, not the common base class.
I have similar base classes for my projects for "Editable" entities which centralizes common fields like CreatedByUserId, CreatedDateTime, etc. The base EnditableEntity does not have a table or any configuration, all configuration is based on the sub-classes. In my case the EditableEntity is abstract
as it pretty much should be, but I don't think that directly affects the mapping. What likely would interfere with mapping and have EF expecting a TPH/TPT/TPC config would be any configuration or DbSet referencing the base class directly.
本文标签: inheritanceIgnoring a base type in Entity Framework Core 9 codefirstStack Overflow
版权声明:本文标题:inheritance - Ignoring a base type in Entity Framework Core 9 code-first - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736306130a1932844.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
ElementBase
should be abstract. Do you really want to allownew ElementBase()
? It also doesn't really need a generic parameter, since it doesn't use it for anything. Though if you never obtain aEntityTypeBuilder<ElementBase>
then it shouldn't be mapped as part of a heirachy. – Jeremy Lakeman Commented Nov 22, 2024 at 2:22XxxBase
classes would be instantiated, but not in the context of the ORM. I also agree with anyone who thinks that not marking the classes as abstract (i.e. embedding extra functionality in them) is a questionable design choice. – Raheel Khan Commented Nov 22, 2024 at 6:45