Let’s say I have two classes representing two tables in the DB
public partial class TableA
{
public int TableAId { get; set; }
}
public partial class TableB
{
public int TableBId { get; set; }
}
and then in other files I’d have
public interface IId
{
int Id { get; set; }
}
public partial class TableA : IId
{
int IId.Id { get => this.TableAId; set => this.TableAId = value; }
}
public partial class TableB : IId
{
int IId.Id { get => this.TableBId; set => this.TableBId = value; }
}
I know that the classes are substituted with CastleProxy
instances and such but I have no idea how exactly this would impact the behaviour of EF Core.
Note: underlying DB is SQL Server
8
Its perfectly legal to use inheritance for entity classes,
when you use inherited entities the EF creates one more extra column in the SQL table. You can add the [NotMapped]
data annotation to the property which is derived.
// @nuget: EntityFramework
using System;
using System.Linq;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations.Schema;
public class Program
{
public static void Main()
{
using (var context = new EntityContext())
{
context.Ingredients.Add(new Vegetable() { ID=1, Name ="Carrot"});
context.Ingredients.Add(new Vegetable() { ID=2, Name ="Chilly"});
context.Ingredients.Add(new Ingredient() { ID=3 });//Name ="Capscicum"
context.SaveChanges();
}
using (var context = new EntityContext())
{
var list = context.Ingredients.ToList();
FiddleHelper.WriteTable("Ingredients", list);
}
}
public class EntityContext : DbContext
{
public EntityContext() : base(FiddleHelper.GetConnectionStringSqlServer())
{
}
public DbSet<Ingredient> Ingredients { get; set; }
}
public class Ingredient
{
public int ID{get;set;}
}
public class Vegetable: Ingredient
{
public string Name { get; set; }
[NotMapped]
public int IDX{get{ return this.ID; } set { this.ID = value; }}
}
}
There’s no inheritance in the question. EF like all ORMs deals with application entities, not tables. Implementing an interface isn’t an inheritance relation. There’s no Manager:Person
relation, there are two unrelated Table
classes, which is a pretty big warning sign.
If the question gets rephrased to Is it OK to use interfaces in entities
the answer is It depends on the actual case
. And without knowing what other interfaces are used in the application, or how IId
is used beyond this code, I’d say it’s not a good use.
If we want a uniform Id
in code but different column names we could use the following code. EF doesn’t need it though and will treat Id
as a primary key by convention :
public class Tag:IId
{
[Column("TagId")]
public int Id { get; set; }
...
}
EF itself needs no IId
or IEntity
interfaces. Interfaces are hard-coded while the lambdas and Expression<>
s used by LINQ are far more dynamic and flexible, while still type safe. EF itself can use naming conventions to detect not just primary keys but relations as well.
EF out of the box will tread Id
or TypeXYZId
properties with a primitive type as primary keys. It will treat properties with names matching other entities as relations. In this example the Id columns are treated as primary keys automatically while Tags
and Posts
are treated as relations based on columns named PostId, TagId. In EF Core 7 and later even the bridge table PostTags will be inferred automatically :
public class Post
{
public int Id { get; set; }
public ICollection<Tag> Tags { get; } = new List<Tag>();
}
public class Tag
{
public int Id { get; set; }
public ICollection<Post> Posts { get; } = new List<Post>();
}
EF would recognize Tag.TagId
as a primary key too
public class Tag
{
public int TagId { get; set; }
public ICollection<Post> Posts { get; } = new List<Post>();
}
If we wanted to use Id
in the entity but TagId
in the table we could use
public class Tag
{
[Column("TagId")]
public int Id { get; set; }
...
}
After that implementing IId doesn’t need partial classes:
public class Tag:IId
{
[Column("TagId")]
public int Id { get; set; }
...
}
We can avoid modifying the entities themselves too, if we use fluent configuration