C# 实体框架核心-两个实体之间的多个一对多关系
我有两个实体-团队和游戏。一个队可以有很多比赛(一对多) 所以看起来是这样的:C# 实体框架核心-两个实体之间的多个一对多关系,c#,database,entity-framework-core,C#,Database,Entity Framework Core,我有两个实体-团队和游戏。一个队可以有很多比赛(一对多) 所以看起来是这样的: public class Team { public int Id { get; set; } public string Name { get; set; } public ICollection<Game> Games { get; set; } } public class Game { public i
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; }
}
公共类团队
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共ICollection游戏{get;set;}
}
公开课游戏
{
公共int Id{get;set;}
公共日期时间日期{get;set;}
public int TeamId{get;set;}
公共团队{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; }
}
公共类团队
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共ICollection家庭游戏{get;set;}
公共ICollection AwayGames{get;set;}
}
公开课游戏
{
公共int Id{get;set;}
公共日期时间日期{get;set;}
public int HomeTeamId{get;set;}
公共团队主队{get;set;}
公共int{get;set;}
公共团队AwayTeam{get;set;}
}
这样做会混淆实体框架,它无法决定如何解决关系
有什么想法吗?您必须告诉实体框架在一个关联中涉及两个实体中的哪些属性。在fluent mapping 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);
}
模型创建时受保护的覆盖无效(ModelBuilder ModelBuilder)
{
modelBuilder.Entity().HasMany(t=>t.HomeGames)
.WithOne(g=>g.HomeTeam)
.HasForeignKey(g=>g.HomeTeamId);
modelBuilder.Entity().HasMany(t=>t.AwayGames)
.带一个(g=>g.AwayTeam)
.HasForeignKey(g=>g.AwayTeamId).OnDelete(DeleteBehavior.Restrict);
}
您必须使用fluent API,因为默认情况下,EF将尝试使用级联删除创建两个外键。SQL Server不允许这样做,因为它臭名昭著的“多级联路径”限制。其中一个键不应该是级联的,这只能由fluent API配置。基于您可以使用数据注释
数据注释
有两种数据注释可用于配置
关系、[ForeignKey]和[InverseProperty]
[外键]
您可以使用数据注释来配置
属性应用作给定对象的外键属性
关系这通常在启用外键属性时完成
没有被惯例发现的
[逆属性]
您可以使用数据注释来配置
从属实体和主体实体对上的导航属性。
这通常在存在多对导航时完成
两个实体类型之间的属性
公共类团队
{
公共int Id{get;set;}
公共字符串名称{get;set;}
[逆属性(“主队”)]
公共ICollection家庭游戏{get;set;}
[反向属性(“AwayTeam”)]
公共ICollection AwayGames{get;set;}
}
公开课游戏
{
公共int Id{get;set;}
公共日期时间日期{get;set;}
public int HomeTeamId{get;set;}
[ForeignKey(“HomeTeamId”)]
公共团队主队{get;set;}
公共int{get;set;}
[外键(“AwayTeamId”)]
公共虚拟团队AwayTeam{get;set;}
}
如果使用db.Database.Migrate(),则会出现错误
System.Data.SqlClient.SqlException:'引入外键
表“Games”上的约束“FK\U Games\U Team\U HomeTeamId”可能导致
循环或多个级联路径。指定ON DELETE NO ACTION或ON
不更新任何操作,或修改其他外键约束。不能
创建约束或索引。请参阅以前的错误
您可以将HomeTeamId设置为可为空
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; }
}
公共类团队
{
公共int Id{get;set;}
公共字符串名称{get;set;}
[逆属性(“主队”)]
公共ICollection家庭游戏{get;set;}
[反向属性(“AwayTeam”)]
公共ICollection AwayGames{get;set;}
}
公开课游戏
{
公共int Id{get;set;}
公共日期时间日期{get;set;}
public int?HomeTeamId{get;set;}
[ForeignKey(“HomeTeamId”)]
公共团队主队{get;set;}
公共int?AwayTeamId{get;set;}
[外键(“AwayTeamId”)]
公共虚拟团队AwayTeam{get;set;}
}
或者看
- 这里是我测试并运行的完整代码(db first而不是code first)
- 对于代码,请先使用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(); } } }
使用系统; 使用System.Collections.Generic; 使用System.ComponentModel.DataAnnotations.Schema; 使用Microsoft.EntityFrameworkCore; 命名空间堆栈溢出54196199 { 公开课小组 { 公共int Id{get;set;} 公共字符串名称{get;set;} [逆属性(“主队”)] 公共ICollection家庭游戏{get;set;} [反向属性(“AwayTeam”)] 公共ICollection AwayGames{get;set;} } 公开课游戏 { 公共int Id{get;set;} 公共日期时间日期{get;set;} public int HomeTeamId{get;set;} [ForeignKey(“HomeTeamId”)] 公共团队主队{get;set;} 公共int{get;set;} [外键(“AwayTeamId”)] 公共团队AwayTeam{get;set;} } 公共类MyContext:DbContext { 公共DbSet游戏{get;set;} 公共DbSet团队{get;set;} 配置时受保护的覆盖无效(DBContextOptions Builder Options Builder) { o
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(); } } }
<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>