c# - EF Core 类型配置添加冗余 FK
问题描述
我正在尝试配置 EFCore:Square
和中的实体之间的关系Position
。Position 与 square named 之间存在一对(位置)对多(squares)的关系squares
,以及Square
namedenPassentTakablePawnOfWhite
和之间的两个一对一关系enPassentTakablePawnOfBlack
。请注意,两个实体中的 FK 和 PK 都是影子属性:
public class PositionTypeConfiguration : IEntityTypeConfiguration<Position>
{
public void Configure(EntityTypeBuilder<Position> builder)
{
builder.ToTable("Positions");
builder.Property<Guid>("BoardId");
builder.Property<Guid?>("CurrentPositionId");
builder.HasOne<Board>().WithMany("previosPositions").HasForeignKey("BoardId");
builder.HasOne<Board>().WithOne("currentPosition").IsRequired(false).HasForeignKey<Position>("CurrentPositionId");
builder.HasMany<Square>("squares").WithOne().HasForeignKey("PositionId");
builder.Property<Guid?>("EnPassentTakableWhitePawnId");
builder.Property<Guid?>("EnPassentTakableBlackPawnId");
builder.HasOne<Square?>("enPassentTakablePawnOfWhite").WithOne().HasForeignKey<Position>("EnPassentTakableWhitePawnId");
builder.HasOne<Square?>("enPassentTakablePawnOfBlack").WithOne().HasForeignKey<Position>("EnPassentTakableBlackPawnId");
builder.Property("canWhiteCastleKingSide");
builder.Property("canWhiteCastleQueenSide");
builder.Property("canBlackCastleKingSide");
builder.Property("canBlackCastleQueenSide");
builder.Property("_50MovesRuleCounter");
builder.Property<Guid>("Id").ValueGeneratedOnAdd();
builder.HasKey("Id");
}
}
public class SqaureTypeConfiguration : IEntityTypeConfiguration<Square>
{
public void Configure(EntityTypeBuilder<Square> builder)
{
builder.ToTable("Sqaures");
builder.Property(s => s.File);
builder.Property<Guid>("PositionId");
builder.Property(s => s.Row);
//this is FK to some other, irrelavant entity.
builder.HasOne(s => s.Occupier).WithOne().IsRequired(false).HasForeignKey<Square>("OccupierId").IsRequired(false);
builder.Property<Guid>("Id");
builder.HasKey("Id");
builder.Property<Guid?>("OccupierId").IsRequired(false);
}
}
问题是,在迁移生成时,迁移创建了以下两个 FK 到Position
in Square
:
public partial class ChangedBoard : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
/...
migrationBuilder.AddColumn<Guid>(
name: "PositionId1",
table: "Sqaures",
type: "uniqueidentifier",
nullable: true);
migrationBuilder.CreateIndex(
name: "IX_Sqaures_PositionId1",
table: "Sqaures",
column: "PositionId1");
migrationBuilder.AddForeignKey(
name: "FK_Sqaures_Positions_PositionId1",
table: "Sqaures",
column: "PositionId1",
principalTable: "Positions",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
}
//there is also ```"PositionId" in other migration
我建议改为查看此图像,因为它可以更好地说明:
方格表:
职位表:
如您所见,PositionId1
和PositionId
都BoardId
在那里,即使他们没有。(只PositionId
应该存在,作为一对多关系的一部分)这引起了一些实际问题,因为在Position
使用 EFCore 重试实体时,我得到所有平方重复(两次)
这是为什么?我该如何解决?我尝试将显式类型和 FK 名称添加到一对多关系,更改配置顺序等。没有任何效果。
以下是实体:
正方形:
public record Square(Piece? Occupier, int Row, int File) : IComparable<Square>
{
private Square() : this(returnNull())
{
}
private static Piece returnNull()
{
return null;
}
public int Row
{
get; set;
} = Row;
public int File
{
get; set;
} = File;
public Square(Piece? occupier) : this(occupier, 0, 0)
{
this.Occupier = occupier;
}
public void SetLocation(int row, int file)
{
Row = row;
File = file;
}
public int CompareTo(Square? other)
{
if(other is null)
return 1;
int result = this.Row.CompareTo(other.Row);
if(result != 0)
return result;
return this.File.CompareTo(other.File);
}
}
位置:
public record Position
{
private List<Square> squares;
public List<Square> Squares
{
get
{
return squares;
}
}
private int At(int row, int file)
{
return row * 8 + file;
}
private bool canWhiteCastleKingSide;
private bool canWhiteCastleQueenSide;
private bool canBlackCastleKingSide;
private bool canBlackCastleQueenSide;
private Square? enPassentTakablePawnOfWhite;
private Square? enPassentTakablePawnOfBlack;
private const int RowAmount = 8;
private const int FileAmount = 8;
private int _50MovesRuleCounter;
private readonly IDictionary<PieceType, Func<int, int, IEnumerable<Ply>>> possibleMovesGenerationFunctionsDictinary;
//.....
编辑:当我尝试删除两者的整个类型配置时Positions
(squares
除了 PK 配置),从正方形到位置的 FK 仍然存在(只有其中一个)
此外,当我尝试删除Squares
公共属性时,在删除所有类型配置后,定位的 FK 确实消失了,但登机的 FK(根本没有被引用,也不应该在这里)仍然存在。将公共属性的名称从Squares
更改为其他名称不会改变任何内容,我仍然需要此属性,所以我不能删除它。将其标记为 [NoMapped] 会导致相同的结果
解决方案
在您的课程BoardId
中明确定义PositionTypeConfiguration
。如果您不需要它,只需builder.Property<Guid>("BoardId");
从PositionTypeConfiguration
.
现在关于PositionId1
,PositionId
问题。
您使用此行来创建外键
builder.HasMany<Square>("squares").WithOne().HasForeignKey("PositionId");
并且您在班级中具有以下square
集合的字段和属性Position
private List<Square> squares;
public List<Square> Squares
{
get
{
return squares;
}
}
问题是您手动为私有字段创建外键,而 EF 自动为公共属性创建外键。因此,您配置了 2 个外键,因此配置了 2 个属性PositionId1
和PositionId
要解决此问题,请使用此行进行配置
builder.HasMany<Square>(x => x.Squares).WithOne().HasForeignKey("PositionId");
并删除私有字段,如果您希望它是不可变的,您可以改用私有集
public class Position
{
public List<Square> Squares { get; private set; }
}
我也看不到类PositionId
上的属性Square
,没有它,您将无法使用您的模型将其保存到数据库中,因为您已将此列配置为不可为空。
最后一件事是关于record
类型。
EF 核心目前不支持记录类型的更改跟踪,因此如果您需要,最好使用常规类
编辑:
我在您发布的代码中看不到任何可能导致BoardId
出现在Squares
表格中的内容。但是您的项目中的其他一些配置可能会创建它。
推荐阅读
- pycurl - 无法在 kali linux 上运行 theharvester。致命异常:Pycurl:链接时版本比编译时版本旧
- url - SWIFTUI - 如何创建链接到 URL 的图像?
- c# - AssemblyLoadContext 是否隔离静态变量?
- python - 数据分组问题,但基于“窗口”
- php - 编译失败:偏移量 12 处的字符类范围无效
- javascript - 有没有办法 console.log 一个 html 对象的内容?
- reactjs - API调用一旦执行就返回promise对象?
- mysql - 如何将我的路由参数与@mysql/x devAPI 连接起来?
- c# - 如何按照 Fluent Builder 模式使用回调将值添加到上下文
- mysql - SQL 选择多于 1 个联结的地方