有两个独立的实体(源和目标)和一个将一个Source连接到一个Target的可选实体。除了在Source和Target实体上使用SourceTargetBinding类型的导航属性之外,该关系应该如下所示:
模特:
public class Source
{
[Key]
public long SourceID { get; set; }
public string Name { get; set; }
public SourceTargetBinding TargetBinding { get; set; }
}
public class Target
{
[Key]
public long TargetID { get; set; }
public string Name { get; set; }
public SourceTargetBinding SourceBinding { get; set; }
}
public class SourceTargetBinding
{
[Key]
public long SourceID { get; set; }
public long TargetID { get; set; }
public Source Source { get; set; }
public Target Target { get; set; }
}
背景信息:
public class MyContext : DbContext
{
public MyContext() : base("name=MyContextData")
{
}
public DbSet<Source> Sources { get; set; }
public DbSet<Target> Targets { get; set; }
public DbSet<SourceTargetBinding> SourceTargetBindings { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<SourceTargetBinding>()
.HasKey(b => b.SourceID);
modelBuilder.Entity<SourceTargetBinding>()
.HasRequired(b => b.Source)
.WithOptional(s => s.TargetBinding);
modelBuilder.Entity<SourceTargetBinding>()
.HasRequired(b => b.Target)
.WithOptional(t => t.SourceBinding);
base.OnModelCreating(modelBuilder);
}
}
这是生成的迁移。请注意从SourceTargetBindings到Targets的错误外键:
public override void Up()
{
CreateTable(
"dbo.Sources",
c => new
{
SourceID = c.Long(nullable: false, identity: true),
Name = c.String(),
})
.PrimaryKey(t => t.SourceID);
CreateTable(
"dbo.SourceTargetBindings",
c => new
{
SourceID = c.Long(nullable: false),
TargetID = c.Long(nullable: false),
})
.PrimaryKey(t => t.SourceID)
.ForeignKey("dbo.Sources", t => t.SourceID)
.ForeignKey("dbo.Targets", t => t.SourceID)
.Index(t => t.SourceID);
CreateTable(
"dbo.Targets",
c => new
{
TargetID = c.Long(nullable: false, identity: true),
Name = c.String(),
})
.PrimaryKey(t => t.TargetID);
}
如果我从source(Source.TargetBinding)和target(Target.SourceBinding)中删除导航属性,则EF会创建正确的外键。但我需要那些导航属性。
我不知道自己做错了什么。在我看来,TargetID将是FK明显的依赖列。如果有流畅的API语义来指定依赖列,我无法找到它。 Map()不起作用,因为TargetID作为模型中的属性公开(我也需要)。
我还尝试了反向语义 - 在源和目标上使用HasOptional-WithRequired而不是在连接实体上使用HasRequired-WithOptional。我得到了同样不正确的结果。
答案 0 :(得分:0)
问题在于您的联结表。您需要定义composite key,因为您可能有许多SourceId,因此SourceId + TargetId将是唯一的,因此是关键:
public class SourceTargetBinding
{
[Key, Column(Order = 0)]
public long SourceID { get; set; }
[Key, Column(Order = 1)]
public long TargetID { get; set; }
public Source Source { get; set; }
public Target Target { get; set; }
}
您的流利代码变为:
modelBuilder.Entity<SourceTargetBinding>().HasKey(e => new { e.SourceId, e.TargetId });
编辑:如果你想要SourceTargetBinding 0:1,那么它需要用key和FK标记:
public class SourceTargetBinding
{
[Key, ForeignKey("Source")]
public long SourceID { get; set; }
public long TargetID { get; set; }
public Source Source { get; set; }
public Target Target { get; set; }
}
编辑2:
modelBuilder.Entity<SourceTargetBinding>()
.HasRequired(b => b.Target)
.WithOptional(t => t.SourceBinding)
.Map(m => m.MapKey("TargetId"));