Efcore: Navigations 'x' and 'y' were separated into two relationships as ForeignKeyAttribute was specified on navigations on both sides.

Created on 20 Apr 2018  路  5Comments  路  Source: dotnet/efcore

I have foreign keys on both sides (circular references) but I get this warning when adding migration.

Microsoft.EntityFrameworkCore.Model[10612]
Navigations 'Player.Info' and 'PlayerInfo.Player' were separated into two relationships as ForeignKeyAttribute was specified on navigations on both sides.

Is there any way to disable this warning, or better way to solve this? What I'm trying to accomplish is to have history of changes as I need relations to old entries in some of my models. So if I change something I want some of the tables to still reference entries before change. I need circural reference as I want my Player.Info (foreign key) to always point to the most up to date entry.

closed-question

Most helpful comment

@enemyofthedawn I think if your intention is to create two relationships (see below), then you can probably ignore this warning. The warning is basically saying that using ForeignKeyAttribute in this way creates two relationships because it is not uncommon for people to do this by mistake not intending it to create two relationships.

Note for triage: the resulting model for this has two FKs:
```C#
EntityType: Player
Properties:
Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd 0 0 0 -1 0
InfoId (no field, Nullable) Shadow FK Index 1 1 1 0 1
Navigations:
Info (k__BackingField, PlayerInfo) ToPrincipal PlayerInfo 0 -1 2 -1 -1
Keys:
Id PK
Foreign keys:
Player {'InfoId'} -> PlayerInfo {'Id'} Unique ToPrincipal: Info
EntityType: PlayerInfo
Properties:
Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd 0 0 0 -1 0
IsActive (bool) Required 1 1 -1 -1 -1
PlayerId (no field, Nullable) Shadow FK Index 2 2 1 0 1
Navigations:
Player (k__BackingField, Player) ToPrincipal Player 0 -1 2 -1 -1
Keys:
Id PK
Foreign keys:
PlayerInfo {'PlayerId'} -> Player {'Id'} ToPrincipal: Player

However, only one FK constraint is created in the database:
```sql
      CREATE TABLE [PlayerInfo] (
          [Id] int NOT NULL IDENTITY,
          [IsActive] bit NOT NULL,
          [PlayerId] int NULL,
          CONSTRAINT [PK_PlayerInfo] PRIMARY KEY ([Id])
      );

      CREATE TABLE [Player] (
          [Id] int NOT NULL IDENTITY,
          [InfoId] int NULL,
          CONSTRAINT [PK_Player] PRIMARY KEY ([Id]),
          CONSTRAINT [FK_Player_PlayerInfo_InfoId] FOREIGN KEY ([InfoId]) REFERENCES [PlayerInfo] ([Id]) ON DELETE NO ACTION

Doing explicit configuration like this:
```C#
modelBuilder
.Entity()
.HasOne(e => e.Info)
.WithOne()
.HasForeignKey("InfoId");

modelBuilder
.Entity()
.HasOne(e => e.Player)
.WithMany()
.HasForeignKey("PlayerId");
```
also results in the same tables.

All 5 comments

@enemyofthedawn Can you post the code that you are trying to map?

@ajcvickers There you go:

public class PlayerInfo
{
    public int Id { get; set; }

    // is outdated or not (kind of soft-delete)
    public bool IsActive { get; set; }

    [ForeignKey("PlayerId")]
    public virtual Player Player { get; set; }
}

public class Player
{
    public int Id { get; set; }

    // info with IsActive == true, or most up to date one
    [ForeignKey("InfoId")]
    public virtual PlayerInfo Info { get; set; }

    //public virtual IReadOnlyCollection<PlayerInfo> Infos { get; set; }
}

Maybe the better way is to expose just collection of PlayerInfo and query it each time? But I was thinking to simply set the id of active one.

@enemyofthedawn I think if your intention is to create two relationships (see below), then you can probably ignore this warning. The warning is basically saying that using ForeignKeyAttribute in this way creates two relationships because it is not uncommon for people to do this by mistake not intending it to create two relationships.

Note for triage: the resulting model for this has two FKs:
```C#
EntityType: Player
Properties:
Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd 0 0 0 -1 0
InfoId (no field, Nullable) Shadow FK Index 1 1 1 0 1
Navigations:
Info (k__BackingField, PlayerInfo) ToPrincipal PlayerInfo 0 -1 2 -1 -1
Keys:
Id PK
Foreign keys:
Player {'InfoId'} -> PlayerInfo {'Id'} Unique ToPrincipal: Info
EntityType: PlayerInfo
Properties:
Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd 0 0 0 -1 0
IsActive (bool) Required 1 1 -1 -1 -1
PlayerId (no field, Nullable) Shadow FK Index 2 2 1 0 1
Navigations:
Player (k__BackingField, Player) ToPrincipal Player 0 -1 2 -1 -1
Keys:
Id PK
Foreign keys:
PlayerInfo {'PlayerId'} -> Player {'Id'} ToPrincipal: Player

However, only one FK constraint is created in the database:
```sql
      CREATE TABLE [PlayerInfo] (
          [Id] int NOT NULL IDENTITY,
          [IsActive] bit NOT NULL,
          [PlayerId] int NULL,
          CONSTRAINT [PK_PlayerInfo] PRIMARY KEY ([Id])
      );

      CREATE TABLE [Player] (
          [Id] int NOT NULL IDENTITY,
          [InfoId] int NULL,
          CONSTRAINT [PK_Player] PRIMARY KEY ([Id]),
          CONSTRAINT [FK_Player_PlayerInfo_InfoId] FOREIGN KEY ([InfoId]) REFERENCES [PlayerInfo] ([Id]) ON DELETE NO ACTION

Doing explicit configuration like this:
```C#
modelBuilder
.Entity()
.HasOne(e => e.Info)
.WithOne()
.HasForeignKey("InfoId");

modelBuilder
.Entity()
.HasOne(e => e.Player)
.WithMany()
.HasForeignKey("PlayerId");
```
also results in the same tables.

@ajcvickers Because the relationships are cyclic, the foreign key constraint needs to be added out of band of the CREATE TABLE statement:

ALTER TABLE [PlayerInfo] ADD CONSTRAINT [FK_PlayerInfo_Player_PlayerId] FOREIGN KEY ([PlayerId]) REFERENCES [Player] ([Id]) ON DELETE CASCADE;

@bricelam Indeed.

Was this page helpful?
0 / 5 - 0 ratings