Entity Framework Code First - two Foreign Keys from same table

后端 未结 6 1849
别那么骄傲
别那么骄傲 2020-11-22 03:40

I\'ve just started using EF code first, so I\'m a total beginner in this topic.

I wanted to create relations between Teams and Matches:

1 match = 2 teams (ho

相关标签:
6条回答
  • 2020-11-22 03:58

    It's also possible to specify the ForeignKey() attribute on the navigation property:

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

    That way you don't need to add any code to the OnModelCreate method

    0 讨论(0)
  • 2020-11-22 03:58

    This is because Cascade Deletes are enabled by default. The problem is that when you call a delete on the entity, it will delete each of the f-key referenced entities as well. You should not make 'required' values nullable to fix this problem. A better option would be to remove EF Code First's Cascade delete convention:

    modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); 
    

    It's probably safer to explicitly indicate when to do a cascade delete for each of the children when mapping/config. the entity.

    0 讨论(0)
  • 2020-11-22 04:07

    You can try this too:

    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; }
    }
    

    When you make a FK column allow NULLS, you are breaking the cycle. Or we are just cheating the EF schema generator.

    In my case, this simple modification solve the problem.

    0 讨论(0)
  • 2020-11-22 04:13

    InverseProperty in EF Core makes the solution easy and clean.

    InverseProperty

    So the desired solution would be:

    public class Team
    {
        [Key]
        public int TeamId { get; set;} 
        public string Name { get; set; }
    
        [InverseProperty(nameof(Match.HomeTeam))]
        public ICollection<Match> HomeMatches{ get; set; }
    
        [InverseProperty(nameof(Match.GuestTeam))]
        public ICollection<Match> AwayMatches{ get; set; }
    }
    
    
    public class Match
    {
        [Key]
        public int MatchId { get; set; }
    
        [ForeignKey(nameof(HomeTeam)), Column(Order = 0)]
        public int HomeTeamId { get; set; }
        [ForeignKey(nameof(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 Team HomeTeam { get; set; }
        public Team GuestTeam { get; set; }
    }
    
    0 讨论(0)
  • 2020-11-22 04:14

    I know it's a several years old post and you may solve your problem with above solution. However, i just want to suggest using InverseProperty for someone who still need. At least you don't need to change anything in OnModelCreating.

    The below code is un-tested.

    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; }
    }
    

    You can read more about InverseProperty on MSDN: https://msdn.microsoft.com/en-us/data/jj591583?f=255&MSPPError=-2147217396#Relationships

    0 讨论(0)
  • 2020-11-22 04:15

    Try this:

    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);
        }
    }
    

    Primary keys are mapped by default convention. Team must have two collection of matches. You can't have single collection referenced by two FKs. Match is mapped without cascading delete because it doesn't work in these self referencing many-to-many.

    0 讨论(0)
提交回复
热议问题