I am trying to configure a relationship between to entities in EFCore: Square and Position. Position has one (position) to many (squares) relationship with square named squares, as well as two one - to - one relationship between Square named enPassentTakablePawnOfWhite and enPassentTakablePawnOfBlack. Note that both the FKs as well as the PKs in both of the entities are shadow properties:
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);
}
}
The problem is, that upon migration generation, the migration created the following two FKs to 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
I recommend seeing this image instead, because it illustrates better:
Squares table:
Position table:
As you can see, both PositionId1, PositionId and BoardId are in there, even tho they sholden't. (only PositionId should exist, as part of the one-to many relationship)
This has caused some real problems, as upon retrial of a Position entity using EFCore, I get all the squared duplicated (twice)
Why is that? And how can I resolve it? I tried Adding explicit type and FK name to the one-to-many relationship, changed configuration order etc.. nothing has worked.
Here are the entities:
Square:
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);
}
}
Position:
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;
//.....
Edit: when I tried removing the entire type configurations of both Positions and squares (except the PK configuration), the FK from square to position has remained (only one of them)
Also, when I try to remove the Squares public property, after removing all the type configurations, the FK to position DOES go away, but the FK to board (which is not referenced at all, and should also not be here) still stays. changing the name of the public property from Squares to something else changes nothins, and I do still need this property so I cant just delete it. Marking it as [NoMapped] leadsto same result


