[英]Updating connected entities with one-to-many relationships in entity framework core
[英]Entity Framework Core - Multiple one-to-many relationships between two entities
我有两个实体 - 团队和游戏 。 一个团队可以有很多游戏(一对多)。
所以这看起来像这样:
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; }
}
这很好用,但我希望通过将游戏分为两类 - Home和Away游戏来使其更加精致。 然而,这将引入两个实体之间的另一种关系,我不知道如何定义它。
我想它会是这样的?
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; }
}
这样做会混淆实体框架,它无法决定如何解决关系。
有任何想法吗?
基于关系 - EF核心| Microsoft Docs您可以使用Data Annotations
数据注释
有两个数据注释可用于配置关系,[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:'在'Games'表上引入FOREIGN KEY约束'FK_Games_Teams_HomeTeamId'可能会导致循环或多个级联路径。 指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他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; }
}
或者参见Cascade Delete - EF Core | Microsoft Docs
这里测试和工作的完整代码( db首先不是代码优先 )
代码首先使用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>
您必须告诉实体框架两个实体中的哪些属性涉及一个关联。 在流畅的映射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);
}
您必须使用fluent API,因为默认情况下,EF将尝试使用级联删除创建两个外键。 由于其臭名昭着的“多级联路径”限制,SQL Server将不允许这样做。 其中一个键不应该是级联,只能通过流畅的API进行配置。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.