Entity Framework Core - множественные отношения один-ко-многим между двумя объектами - PullRequest
0 голосов
/ 15 января 2019

У меня есть две сущности - Команда и Игра . У команды может быть много игр (один-ко-многим).

Так это будет выглядеть примерно так:

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

        public ICollection<Game> Games { get; set; }
    }

 public class Game
    {
        public int Id { get; set; }
        public DateTime Date { get; set; }

        public int TeamId { get; set; }
        public Team Team { get; set; }
    }

Это хорошо работает, но я хочу сделать его немного более изысканным, разделив игры на две категории - игры для дома и в гостях. Это, однако, введет другое отношение между двумя сущностями, и я не уверен, как его определить.

Я полагаю, это будет что-то вроде этого?

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

        public ICollection<Game> HomeGames { get; set; }
        public ICollection<Game> AwayGames { get; set; }
    }

public class Game
    {
        public int Id { get; set; }
        public DateTime Date { get; set; }

        public int HomeTeamId { get; set; }
        public Team HomeTeam { get; set; }

        public int AwayTeamId{ get; set; }
        public Team AwayTeam { get; set; }
    }

Это сбивает с толку Entity Framework, и он не может решить, как установить отношения.

Есть идеи?

Ответы [ 2 ]

0 голосов
/ 15 января 2019

База Отношения - EF Core | Документы Microsoft вы можете использовать аннотации данных

Аннотации данных

Есть две аннотации данных, которые можно использовать для настройки отношения, [ForeignKey] и [InverseProperty].

[ForeignKey]

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

[InverseProperty]

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

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

        [InverseProperty("HomeTeam")]
        public ICollection<Game> HomeGames { get; set; }

        [InverseProperty("AwayTeam")]
        public ICollection<Game> AwayGames { get; set; }
    }

public class Game
    {
        public int Id { get; set; }
        public DateTime Date { get; set; }

        public int HomeTeamId { get; set; }
        [ForeignKey("HomeTeamId")]
        public Team HomeTeam { get; set; }

        public int AwayTeamId{ get; set; }
        [ForeignKey("AwayTeamId")]
        public virtual Team AwayTeam { get; set; }
    }

если вы используете db.Database.Migrate (), вы получите ошибку

System.Data.SqlClient.SqlException: 'Представление внешнего ключа ограничение 'FK_Games_Teams_HomeTeamId' для таблицы 'Игры' может привести к циклы или несколько каскадных путей. Укажите НА УДАЛИТЬ НЕТ ДЕЙСТВИЙ или ВКЛ ОБНОВИТЬ НЕТ ДЕЙСТВИЯ, или изменить другие ограничения FOREIGN KEY. Не могла создать ограничение или индекс. Смотрите предыдущие ошибки

вы можете сделать HomeTeamId AwayTeamId int? обнуляемым

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

        [InverseProperty("HomeTeam")]
        public ICollection<Game> HomeGames { get; set; }

        [InverseProperty("AwayTeam")]
        public ICollection<Game> AwayGames { get; set; }
    }

public class Game
    {
        public int Id { get; set; }
        public DateTime Date { get; set; }

        public int? HomeTeamId { get; set; }
        [ForeignKey("HomeTeamId")]
        public Team HomeTeam { get; set; }

        public int? AwayTeamId{ get; set; }
        [ForeignKey("AwayTeamId")]
        public virtual Team AwayTeam { get; set; }
    }

или см. Каскадное удаление - EF Core | Документы Microsoft

  • здесь полный код, который я тестировал и работал ( дБ сначала не код сначала )

  • для первого использования кода int?

  • для Program.cs

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations.Schema;
    using Microsoft.EntityFrameworkCore;
    
    namespace stackoverflow54196199
    {
    
    public class Team
    {
    
        public int Id { get; set; }
        public string Name { get; set; }
    
        [InverseProperty("HomeTeam")]
        public ICollection<Game> HomeGames { get; set; }
    
        [InverseProperty("AwayTeam")]
        public ICollection<Game> AwayGames { get; set; }
    }
    
    public class Game
    {
        public int Id { get; set; }
        public DateTime Date { get; set; }
    
        public int HomeTeamId { get; set; }
        [ForeignKey("HomeTeamId")]
        public Team HomeTeam { get; set; }
    
        public int AwayTeamId { get; set; }
        [ForeignKey("AwayTeamId")]
        public Team AwayTeam { get; set; }
    }
    
    
    public class MyContext : DbContext
    {
        public DbSet<Game> Games { get; set; }
        public DbSet<Team> Teams { get; set; }
    
    
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer("Server=.;Integrated Security=true;Initial Catalog=stackoverflow54196199;Persist Security Info=False;");
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            var db = new MyContext();
            foreach (var game in db.Games.Include(i => i.AwayTeam).Include(i => i.HomeTeam))
            {
                Console.WriteLine(game.HomeTeam.Name);
                Console.WriteLine(game.AwayTeam.Name);
    
            }
            Console.ReadLine();
        }
    }
    }
    
  • для stackoverflow54196199.csproj

    <PropertyGroup>
      <OutputType>Exe</OutputType>
      <TargetFramework>netcoreapp2.1</TargetFramework>
    </PropertyGroup>
    
    <ItemGroup>
      <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.0" />
      <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="2.1.0" />
      <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.1.0" />
     </ItemGroup>
    

0 голосов
/ 15 января 2019

Вы должны сообщить Entity Framework, какие свойства в обоих объектах участвуют в одной ассоциации. В API беглого отображения это:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Team>().HasMany(t => t.HomeGames)
        .WithOne(g => g.HomeTeam)
        .HasForeignKey(g => g.HomeTeamId);
    modelBuilder.Entity<Team>().HasMany(t => t.AwayGames)
        .WithOne(g => g.AwayTeam)
        .HasForeignKey(g => g.AwayTeamId).OnDelete(DeleteBehavior.Restrict);
}

Вы должны использовать свободный API, потому что по умолчанию EF попытается создать два внешних ключа с каскадным удалением. SQL Server не допустит этого из-за печально известного ограничения «нескольких каскадных путей». Один из ключей не должен быть каскадным, его можно настроить только с помощью свободного API.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...