Entity Framework Code First - два внешних ключа из одной таблицы - PullRequest
241 голосов
/ 06 апреля 2011

Я только что начал использовать код EF, поэтому я абсолютный новичок в этой теме.

Я хотел создать отношения между командами и матчами: 1 матч = 2 команды (дома, в гостях) и результат. Я думал, что такую ​​модель легко создать, поэтому начал писать код:

public class Team
{
    [Key]
    public int TeamId { get; set;} 
    public string Name { get; set; }

    public virtual ICollection<Match> Matches { get; set; }
}


public class Match
{
    [Key]
    public int MatchId { get; set; }

    [ForeignKey("HomeTeam"), Column(Order = 0)]
    public int HomeTeamId { get; set; }
    [ForeignKey("GuestTeam"), Column(Order = 1)]
    public int GuestTeamId { get; set; }

    public float HomePoints { get; set; }
    public float GuestPoints { get; set; }
    public DateTime Date { get; set; }

    public virtual Team HomeTeam { get; set; }
    public virtual Team GuestTeam { get; set; }
}

И я получаю исключение:

Ссылочные отношения приведут к циклической ссылке, которая не допускается. [Имя ограничения = Match_GuestTeam]

Как создать такую ​​модель с двумя внешними ключами для одной таблицы? ТИА.

Ответы [ 5 ]

280 голосов
/ 06 апреля 2011

Попробуйте:

public class Team
{
    public int TeamId { get; set;} 
    public string Name { get; set; }

    public virtual ICollection<Match> HomeMatches { get; set; }
    public virtual ICollection<Match> AwayMatches { get; set; }
}

public class Match
{
    public int MatchId { get; set; }

    public int HomeTeamId { get; set; }
    public int GuestTeamId { get; set; }

    public float HomePoints { get; set; }
    public float GuestPoints { get; set; }
    public DateTime Date { get; set; }

    public virtual Team HomeTeam { get; set; }
    public virtual Team GuestTeam { get; set; }
}


public class Context : DbContext
{
    ...

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Match>()
                    .HasRequired(m => m.HomeTeam)
                    .WithMany(t => t.HomeMatches)
                    .HasForeignKey(m => m.HomeTeamId)
                    .WillCascadeOnDelete(false);

        modelBuilder.Entity<Match>()
                    .HasRequired(m => m.GuestTeam)
                    .WithMany(t => t.AwayMatches)
                    .HasForeignKey(m => m.GuestTeamId)
                    .WillCascadeOnDelete(false);
    }
}

Первичные ключи сопоставлены по умолчанию.Команда должна иметь две коллекции матчей.Вы не можете иметь одну коллекцию, на которую ссылаются два ФК.Сопоставление сопоставляется без каскадного удаления, потому что оно не работает при самообращении «многие ко многим».

51 голосов
/ 16 января 2013

Также можно указать атрибут ForeignKey() в свойстве навигации:

[ForeignKey("HomeTeamID")]
public virtual Team HomeTeam { get; set; }
[ForeignKey("GuestTeamID")]
public virtual Team GuestTeam { get; set; }

Таким образом, вам не нужно добавлять код к методу OnModelCreate

37 голосов
/ 26 июня 2016

Я знаю, что это пост за несколько лет, и вы можете решить свою проблему с помощью вышеуказанного решения. Тем не менее, я просто хочу предложить использовать InverseProperty для тех, кто все еще нуждается. По крайней мере, вам не нужно ничего менять в OnModelCreating.

Приведенный ниже код не протестирован.

public class Team
{
    [Key]
    public int TeamId { get; set;} 
    public string Name { get; set; }

    [InverseProperty("HomeTeam")]
    public virtual ICollection<Match> HomeMatches { get; set; }

    [InverseProperty("GuestTeam")]
    public virtual ICollection<Match> GuestMatches { get; set; }
}


public class Match
{
    [Key]
    public int MatchId { get; set; }

    public float HomePoints { get; set; }
    public float GuestPoints { get; set; }
    public DateTime Date { get; set; }

    public virtual Team HomeTeam { get; set; }
    public virtual Team GuestTeam { get; set; }
}

Подробнее об InverseProperty можно узнать на MSDN: https://msdn.microsoft.com/en-us/data/jj591583?f=255&MSPPError=-2147217396#Relationships

13 голосов
/ 20 ноября 2013

Это потому, что каскадные удаления по умолчанию включены. Проблема в том, что когда вы вызываете delete для объекта, он также удаляет каждый из объектов, на которые ссылается f-key. Вы не должны делать «обязательные» значения обнуляемыми, чтобы решить эту проблему. Лучшим вариантом было бы удалить соглашение EF Code First каскадного удаления:

modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); 

Вероятно, безопаснее явно указать, когда выполнять каскадное удаление для каждого из дочерних элементов при отображении / настройке. сущность.

13 голосов
/ 10 января 2012

Вы также можете попробовать это:

public class Match
{
    [Key]
    public int MatchId { get; set; }

    [ForeignKey("HomeTeam"), Column(Order = 0)]
    public int? HomeTeamId { get; set; }
    [ForeignKey("GuestTeam"), Column(Order = 1)]
    public int? GuestTeamId { get; set; }

    public float HomePoints { get; set; }
    public float GuestPoints { get; set; }
    public DateTime Date { get; set; }

    public virtual Team HomeTeam { get; set; }
    public virtual Team GuestTeam { get; set; }
}

Когда вы задаете для столбца FK разрешение NULLS, вы прерываете цикл.Или мы просто обманываем генератор схемы EF.

В моем случае эта простая модификация решает проблему.

...