实体框架核心中两个实体之间的一对多和一对一关系

时间:2020-10-18 11:24:16

标签: c# entity-framework-core

我想在Entity Framework Core 3.1中为TeamPlayers建模。每个团队有很多球员,每个球员只有一个团队。此外,每个团队的球员名单中都有一名队长。如何将Fluent Api写成CaptainPlayer之间的关系(一对一)?

public class Team
{
    public int Id { get; set; }
    public string Name { get; set; }
    
    public int? CaptainId { get; set; }
    public Player Captain { get; set; }
    
    public ICollection<Player> Players { get; set; }
}

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

我尝试了以下代码

builder.Entity<Team>()
    .HasOne(e => e.Captain)
    .WithOne()
    .HasForeignKey<Team>(e => e.CaptainId)
    .OnDelete(DeleteBehavior.Restrict);

builder.Entity<Team>()
    .HasMany(g => g.Players)
    .WithOne(s => s.Team)
    .HasForeignKey(s => s.TeamId);

但是此代码生成了两个一对多的关系...

1 个答案:

答案 0 :(得分:0)

过去几天我一直在尝试这样的事情,在尝试了各种数据注释和 Fluent API 废话之后,我能想出的最简洁的解决方案非常简单,两者都不需要。它只需要将“私有”构造函数添加到注入“DbContext”对象的 Team 类(如果使用延迟加载,则为“受保护”构造函数)。只需将您的“Team”和“Player”类设置为正常的一对多关系,并且您的数据库上下文现在可从“Team”实体中使用,您可以使“Captain”属性简单地从以下位置返回查询使用 Find() 方法的数据库。 Find() 方法也使用了缓存,因此如果多次调用 getter,它只会访问一次数据库。

这是关于此能力的文档:https://docs.microsoft.com/en-us/ef/core/modeling/constructors#injecting-services

注意:'Captain' 属性是只读的。要修改它,请设置“CaptainId”属性。

class Team
{
    public Team() { }
    private MyDbContext Context { get; set; }
    // make the following constructor 'protected' if you're using Lazy Loading
    private Team(MyDbContext Context) { this.Context = Context; }

    public int ID { get; set; }
    public string Name { get; set; }
    public int? CaptainID { get; set; }
    public Player Captain { get { return Context.Players.Find(CaptainID); } }
}

class Player
{
    public int ID { get; set; }
    public string Name { get; set; }
    public int TeamID { get; set; }
    public Team Team { get; set; }
}