我有以下对象:
public class Foo<TEntity>
{
public int Id {get; set;}
public ICollection<TEntity> Tasks {get; set;}
}
上述实体的类型配置为:
public abstract class FooConfig<TEntity> : IEntityTypeConfiguration<Foo<TEntity>>
{
public virtual void Configure(EntityTypeBuilder<Foo<TEntity>> builder)
{
builder.ToTable("foo")
builder.HasKey(x => x.Id);
}
}
我有 2 个使用抽象类的 DbSet(Bar 和 Spam 与 Foo 具有多对一关系):
DbSet <Foo<Bar>> BarFoo
DbSet <Foo<Spam>> SpamFoo
他们的配置是:
public class Bar
{
public int Id { get; set; }
public Foo<Bar> Foo { get; set; }
}
public class BarFooConfig : FooConfig<Bar>
{
public override void Configure(EntityTypeBuilder<Foo<Bar>> builder)
{
base.Configure(builder);
builder.HasMany(x => x.Tasks)
.WithOne(x => x.Foo)
.HasForeignKey(x => x.FooId)
}
}
public class Spam
{
public int Id { get; set; }
public Foo<Spam> Foo { get; set; }
}
public class SpamFooConfig : FooConfig<Spam>
{
public override void Configure(EntityTypeBuilder<Foo<Spam>> builder)
{
base.Configure(builder);
builder.HasMany(x => x.Tasks)
.WithOne(x => x.Foo)
.HasForeignKey(x => x.FooId)
}
}
但是当我运行代码时出现以下错误:
不能将表“Foo”用于实体类型“Foo”,因为它用于实体类型“Foo”并且它们的主键之间没有关系
如果需要更多详细信息,请告诉我
如果您不关心单个
Foo
是否可以同时拥有 Bar
和 Spam
子记录,那么简单的答案就是删除泛型并定义两个导航。
public class Foo
{
public int Id {get; set;}
public ICollection<Spam> Spam {get; set;}
public ICollection<Bar> Bar {get; set;}
}
否则,您需要定义一个 table-per-heirachy,向 foo 表添加一个鉴别器 [shadow] 属性。
public abstract class Foo{
public int Id {get; set;}
}
public class Foo<TEntity> : Foo{
public ICollection<TEntity> Tasks {get; set;}
}
那么示例的其余部分可能无需任何进一步的显式配置即可运行。因为 EF Core 将发现模型其余部分中使用和配置的每个
Foo<T>
。
然后,每当您查询导航属性时,EF Core 都会向 sql join 子句添加鉴别器测试。
尽管您可以按照有关如何显式定义鉴别器的文档,而不是依赖 EF Core 来定义影子属性。
我通过这样的研究得到了结果。
定义 IGenericConfiguration:
public interface IGenericConfiguration<T> : IEntityTypeConfiguration<T> where T : class
{
public void SpecialConfigure(EntityTypeBuilder<T> builder);
}
在此输入代码
并定义通用配置:
public abstract class GenericConfiguration<T> : IGenericConfiguration<T> where T : BaseEntitiy
{
public void Configure(EntityTypeBuilder<T> builder)
{
builder.Property(x => x.lastModifiedDate).HasColumnType("timestamp");
builder.Property(x => x.createDate).HasColumnType("timestamp");
SpecialConfigure(builder);
}
public virtual void SpecialConfigure(EntityTypeBuilder<T> builder) { }
}
可以在GenericConfiguration的Config功能下进行各部分通用的conf设置
特定于实体的配置可以定义如下:
public class TestConfiguration : GenericConfiguration<Test>
{
public override void SpecialConfigure(EntityTypeBuilder<Test> builder)
{
builder.Property(x => x.test).HasColumnType("VARCHAR(100)");
}
}