假设我有4个接口,如下所示:
interface IMain
{
ICollection<ISub> Subs { get; set; }
}
interface ISub
{
ICollection<ISubPart> SubParts { get; set; }
}
interface IPart
{
ICollection<ISubPart> SubParts { get; set; }
}
interface ISubPart
{
ISub Sub { get; set; }
IPart Part { get; set; }
}
最终目标是让我在一个类库中使用这些接口,并在另一个类库中实现它们。
如果我尝试实现接口,则包含的集合或对象仍必须是接口类型而不是类类型。例如:
public class Sub : ISub
{
ICollection<ISubPart> SubParts { get; set; }
}
我正在使用Entity Framework和EF Migrations。当我尝试运行迁移时,它失败并显示错误:
The entity type 'MyProject.ISubPart' provided for the argument 'clrType' must be a reference type.
为了试图绕过这个,我想我可以将类型作为通用传递。在我到达ISubPart之前,这很容易做到,因为ISubPart必须使用循环引用返回父级的泛型。所以,像这样:
interface ISubPart<TSub, TPart>
where TSub : class
where TPart : class
{
TSub Sub { get; set; }
TPart Part { get; set; }
}
但是,如果ISub需要传入的泛型类型来定义ISubPart,那么ISubPart的泛型也需要传入包含类型。所以,我几乎需要以下内容,我知道不存在:
interface ISubPart<TSub<TSubPart>, TPart>
where TSub : class
where TSubPart : this
where TPart : class
{
TSub<TSubPart> Sub { get; set; }
TPart Part { get; set; }
}
这是我的DBContext:
public abstract class MyDbContext : MyDbContext<Main, Sub, Part>
{
protected MyDbContext() { }
public MyDbContext(DbContextOptions options) : base(options) { }
}
public abstract class MyDbContext<TMain, TSub, TPart> : DbContext
where TMain : Main
where TSub : Sub
where TPart : Part
{
protected MyDbContext() { }
public MyDbContext(DbContextOptions options) : base(options) { }
public DbSet<TMain> Mains { get; set; }
public DbSet<TSub> Subs { get; set; }
public DbSet<TPart> Parts { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<SubPart>()
.HasOne(o => o..Sub)
.WithMany(m => m.SubParts as List<SubPart>)
.HasForeignKey(f => f.SubId);
builder.Entity<SubPart>()
.HasOne(o => o.Part)
.WithMany(m => m.SubParts as List<SubPart>)
.HasForeignKey(f => f.SubId);
base.OnModelCreating(builder);
}
}
我不能成为第一个遇到这个问题的人。提前谢谢。
答案 0 :(得分:2)
要使用EF Core执行此操作,您需要在导航表达式中进行投射:
builder.Entity<SubPart>()
.HasOne(o => (Sub)o.Sub)
.WithMany(m => m.SubParts)
.HasForeignKey(f => f.Id);
builder.Entity<SubPart>()
.HasOne(o => (Part)o.Part)
.WithMany(m => m.SubParts)
.HasForeignKey(f => f.Id);
答案 1 :(得分:1)
以下解决方案适用于我(包括使用具体类创建EF数据库
interface IMain<TSub, TPart, TSubPart>
where TSubPart : ISubPart<TSub, TPart, TSubPart>
where TSub : ISub<TSub, TPart, TSubPart>
where TPart : IPart<TSub, TPart, TSubPart>
{
ICollection<TSub> Subs { get; set; }
}
interface ISub<TSub, TPart, TSubPart>
where TSub : ISub<TSub, TPart, TSubPart>
where TPart : IPart<TSub, TPart, TSubPart>
where TSubPart : ISubPart<TSub, TPart, TSubPart>
{
ICollection<TSubPart> SubParts { get; set; }
}
interface IPart<TSub, TPart, TSubPart>
where TPart : IPart<TSub, TPart, TSubPart>
where TSub : ISub<TSub, TPart, TSubPart>
where TSubPart : ISubPart<TSub, TPart, TSubPart>
{
ICollection<TSubPart> SubParts { get; set; }
}
interface ISubPart<TSub, TPart, TSubPart>
where TSubPart : ISubPart<TSub, TPart, TSubPart>
where TSub : ISub<TSub, TPart, TSubPart>
where TPart : IPart<TSub, TPart, TSubPart>
{
TSub Sub { get; set; }
TPart Part { get; set; }
}
class SubPart : ISubPart<Sub, Part, SubPart>
{
public long Id { get; set; }
public Sub Sub { get; set; }
public Part Part { get; set; }
}
class Sub : ISub<Sub, Part, SubPart>
{
public long Id { get; set; }
public ICollection<SubPart> SubParts { get; set; }
}
class Part : IPart<Sub, Part, SubPart>
{
public long Id { get; set; }
public ICollection<SubPart> SubParts { get; set; }
}
class Main : IMain<Sub, Part, SubPart>
{
public long Id { get; set; }
public ICollection<Sub> Subs { get; set; }
}
class MyContext : DbContext
{
public DbSet<Main> MainEntities { get; set; }
}
正如您所看到的,EF使用的具体实现并不是真正可以自由支持多种类型,只有接口可以支持多种类型。