如何阻止Entity Framework Core使用表-层次结构映射(TPH)?
我在使用MongoDB.EntityFrameworkCore。
我有3个类:Pod、Planet、Asteroid,它们继承自SpaceObject
我想对Planet和Asteroid使用默认的表层次映射(TPH),把这些实体保存到一个SpaceObjects集合中,使用默认的判别器_t。
但我想把Pod实体单独保存到它们自己的Pods集合中,因此在这种情况下只使用Table-Per-Type映射(TPT)。
我尝试在 Pod 上使用属性(特性)或在模型创建时指定集合:
[Collection("Pods")]
public class Pod : SpaceObject
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Pod>().ToCollection("Pods");
}
这不行:pods总是被保存到 SpaceObjects 集合中。
解决方案
你可以通过为需要使用TPH的实体引入一个中介基类来实现,同时把主基类保留给TPH/TPT继承使用。例如,我为将使用TPH判别器的项引入一个名为SpaceBody的基类:
public abstract class SpaceObject
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
}
[Table("SpaceObjects")]
public abstract class SpaceBody : SpaceObject
{
}
public class Planet : SpaceBody
{
public const string Discriminator = "planet";
}
public class Asteroid : SpaceBody
{
public const string Discriminator = "rock";
}
[Table("Pods")]
public class Pod : SpaceObject
{
public string Pilot { get; set; }
}
在这里我把SpaceBody指向SpaceObjects表,当然你也可以把表命名为 "SpaceBodies" 以减少潜在的混淆,或者为最低层的基类使用一个不同的名称,并将SpaceObject用作TPH映射的子类。
然后在配置中:
modelBuilder.Entity<SpaceBody>()
.HasDiscriminator<string>("Discriminator")
.HasValue<Planet>(Planet.Discriminator)
.HasValue<Asteroid>(Asteroid.Discriminator);
modelBuilder.Entity<Pod>();
DbContext可以包含 DbSet<SpaceBody> 和 DbSet<Pod>,然后对实体和pods进行读写。
测试:
using var context = new TestDbContext();
var planets = new[] {
new Planet { Name = "Earth" },
new Planet{Name = "Mars"}
};
var asteroids = new[] {
new Asteroid { Name = "X-31" },
new Asteroid{Name = "XQ-101"}
};
var pod = new Pod { Name = "Enterprise", Pilot = "Kirk" };
foreach(var planet in planets)
context.SpaceBodies.Add(planet);
foreach(var asteroid in asteroids)
context.SpaceBodies.Add(asteroid);
context.Pods.Add(pod);
context.SaveChanges();
var testPlanets = context.SpaceBodies.OfType<Planet>().ToList();
var testPod = context.Pods.FirstOrDefault(x => x.Pilot == "Kirk");
不过,这确实要求Pods表遵循在基类和TPH表中使用的相同列名。然而,如果你确实想使用不同的列名,例如Pods表使用 "PodName" 而不是 "Name",那么你可以在配置中引入映射变更:
modelBuilder.Entity<Pod>()
.Property(x => x.Name)
.HasColumnName("PodName");
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。