Entity Framework Code First - Optional/required 双向导航
Entity Framework Code First - Optional/required two-way navigation
我有一个类似于以下的代码优先模型:
public class TestContext : DbContext
{
public DbSet<Class1> Class1s { get; set; }
public DbSet<Class2> Class2s { get; set; }
}
public class Class1
{
public int Class1Id { get; set; }
}
public class Class2
{
public int Class2Id { get; set; }
public int Class1Id { get; set; }
public Class1 Class1 { get; set; }
}
有零到多个 Class2 对象引用每个 Class1 对象。每个 Class2 对象都必须引用 Class1 对象。
我想要做的是有一个从 Class1 到 Class2 的可选引用(以跟踪与 Class1 对象关联的 Class2 对象之一),因此我添加了两个属性:
public class Class1
{
public int Class1Id { get; set; }
public int? Class2Id { get; set; }
public Class2 Class2 { get; set; }
}
现在我在 运行 添加迁移时收到以下错误:
Unable to determine the principal end of an association between the
types 'ConsoleApplication15.Class2' and 'ConsoleApplication15.Class1'.
The principal end of this association must be explicitly configured
using either the relationship fluent API or data annotations.
其他 Whosebug 答案表明解决方案是在依赖项上指定外键字段:
public class Class2
{
[Key, ForeignKey("Class1")]
public int Class2Id { get; set; }
public int Class1Id { get; set; }
public Class1 Class1 { get; set; }
}
我的添加迁移命令现已完成,但创建的迁移如下:
public override void Up()
{
DropForeignKey("dbo.Class2", "Class1Id", "dbo.Class1");
DropIndex("dbo.Class2", new[] { "Class1Id" });
DropColumn("dbo.Class2", "Class2Id");
RenameColumn(table: "dbo.Class2", name: "Class1Id", newName: "Class2Id");
DropPrimaryKey("dbo.Class2");
AddColumn("dbo.Class1", "Class2Id", c => c.Int());
AlterColumn("dbo.Class2", "Class2Id", c => c.Int(nullable: false));
AddPrimaryKey("dbo.Class2", "Class2Id");
CreateIndex("dbo.Class2", "Class2Id");
AddForeignKey("dbo.Class2", "Class2Id", "dbo.Class1", "Class1Id");
}
这看起来不像我想要的.. 它删除了 Class2 上的主键并且它在末尾添加的外键是完全错误的。
我如何向 EF 描述我的要求以便它生成正确的模型?
问题是 EF 按照惯例要创建一个 one-to-one relationship,在这种情况下,您需要指定哪个实体是主体。
如果要在每个实体中创建具有不同 PK 的一对一关系,则不能在两个实体中声明 FK 属性。当您配置 one-to-one relationships 时,Entity Framework 要求依赖的主键也是外键(这是您在上一个场景中尝试做的)。
一个解决方案可能是删除 FK 属性(Class2
上的 Class1Id
和 Class1
上的 Class2Id
)并覆盖上下文中的 OnModelCreating
方法添加此配置:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Class2>()
.HasRequired(c2 => c2.Class1).
.WithOptional(c1=>c1.Class2);
}
如果您想使用 FK 属性,您可以创建两个单独的关系,如下所示:
modelBuilder.Entity<Class2>()
.HasRequired(s => s.Class1)
.WithMany()
.HasForeignKey(s => s.Class1Id);
modelBuilder.Entity<Class1>()
.HasOptional(s => s.Class2)
.WithMany()
.HasForeignKey(s => s.Class2Id);
我认为最后一个解决方案更适合您要实现的场景。
我有一个类似于以下的代码优先模型:
public class TestContext : DbContext
{
public DbSet<Class1> Class1s { get; set; }
public DbSet<Class2> Class2s { get; set; }
}
public class Class1
{
public int Class1Id { get; set; }
}
public class Class2
{
public int Class2Id { get; set; }
public int Class1Id { get; set; }
public Class1 Class1 { get; set; }
}
有零到多个 Class2 对象引用每个 Class1 对象。每个 Class2 对象都必须引用 Class1 对象。
我想要做的是有一个从 Class1 到 Class2 的可选引用(以跟踪与 Class1 对象关联的 Class2 对象之一),因此我添加了两个属性:
public class Class1
{
public int Class1Id { get; set; }
public int? Class2Id { get; set; }
public Class2 Class2 { get; set; }
}
现在我在 运行 添加迁移时收到以下错误:
Unable to determine the principal end of an association between the types 'ConsoleApplication15.Class2' and 'ConsoleApplication15.Class1'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
其他 Whosebug 答案表明解决方案是在依赖项上指定外键字段:
public class Class2
{
[Key, ForeignKey("Class1")]
public int Class2Id { get; set; }
public int Class1Id { get; set; }
public Class1 Class1 { get; set; }
}
我的添加迁移命令现已完成,但创建的迁移如下:
public override void Up()
{
DropForeignKey("dbo.Class2", "Class1Id", "dbo.Class1");
DropIndex("dbo.Class2", new[] { "Class1Id" });
DropColumn("dbo.Class2", "Class2Id");
RenameColumn(table: "dbo.Class2", name: "Class1Id", newName: "Class2Id");
DropPrimaryKey("dbo.Class2");
AddColumn("dbo.Class1", "Class2Id", c => c.Int());
AlterColumn("dbo.Class2", "Class2Id", c => c.Int(nullable: false));
AddPrimaryKey("dbo.Class2", "Class2Id");
CreateIndex("dbo.Class2", "Class2Id");
AddForeignKey("dbo.Class2", "Class2Id", "dbo.Class1", "Class1Id");
}
这看起来不像我想要的.. 它删除了 Class2 上的主键并且它在末尾添加的外键是完全错误的。
我如何向 EF 描述我的要求以便它生成正确的模型?
问题是 EF 按照惯例要创建一个 one-to-one relationship,在这种情况下,您需要指定哪个实体是主体。
如果要在每个实体中创建具有不同 PK 的一对一关系,则不能在两个实体中声明 FK 属性。当您配置 one-to-one relationships 时,Entity Framework 要求依赖的主键也是外键(这是您在上一个场景中尝试做的)。
一个解决方案可能是删除 FK 属性(Class2
上的 Class1Id
和 Class1
上的 Class2Id
)并覆盖上下文中的 OnModelCreating
方法添加此配置:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Class2>()
.HasRequired(c2 => c2.Class1).
.WithOptional(c1=>c1.Class2);
}
如果您想使用 FK 属性,您可以创建两个单独的关系,如下所示:
modelBuilder.Entity<Class2>()
.HasRequired(s => s.Class1)
.WithMany()
.HasForeignKey(s => s.Class1Id);
modelBuilder.Entity<Class1>()
.HasOptional(s => s.Class2)
.WithMany()
.HasForeignKey(s => s.Class2Id);
我认为最后一个解决方案更适合您要实现的场景。