我已经创建了这个分层数据库:

enter image description here

每个人都有一名经理,一名经理可以有多名员工.

然后,我创建了这些C#对象:

enter image description here

enter image description here

我将它们添加到建模器中,如下所示:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Person>(p =>
        {
            p.Property(e => e.Id).HasColumnName("Id");
            p.Property(e => e.Name).HasColumnName("Name");

            p.HasOne(e => e.Manager).WithMany(e => e.Employees).HasForeignKey(e => e.ManagerId);
        });

    modelBuilder.Entity<Manager>(m =>
        {
            m.ToTable("Persons");
            m.Property(e => e.Id).HasColumnName("Id");
            m.Property(e => e.Name).HasColumnName("Name");

            m.HasMany(x => x.Employees).WithOne().HasForeignKey(p => p.Id);
        });
}

但我得到的结果是:

enter image description here

预计Mary拥有员工Catherine和Anna,如数据库截图所示.

我做错了什么?

在管理器建模器中更改外键属性时出现错误,例如:

无法将表‘Person’用于实体类型‘Person’,因为它正用于实体类型‘Manager’以及可能的其他实体类型,但没有链接关系.将外键添加到主键属性上的"Person",并指向映射到"Person"的另一个实体类型上的主键

推荐答案

由于EF Core中的实体是表的抽象,因此不能将多个实体映射到单个表.您的表可能看起来有多个实体,但事实并非如此.它实际指示的是您的表是一个self referential个表/实体.

您的实体应该如下所示:

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

   public int? ManagerId {get; set;}
   public Person? Manager {get; set;}
}

此外,您不需要表中的managerName列,因为它是一个导航属性.

EF核心查询将如下所示:

var person = _context.Persons.Include(p=>p.Manager)....

然后,您可以通过以下方式获取经理名称:

var managerName = person.Manager.Name;

若要获取上述人员管理的人员:

var managedPeoples = _context.Persons.Where(p=> p.ManagerId == person.Id); 

OnModelCreating中不需要额外的配置,除非您想要重命名您的表/列名称或添加额外的索引/约束.

Csharp相关问答推荐

应用程序启动时出现错误:操作无法同时使用表单和SON主体参数

如何定义所有项目的解决方案版本?

使用GeneratedComInterfaceProperty的.NET 8 COM类对于VB 6/SYS或ALEViewer不可见

如何使用Automapper映射两个嵌套列表

不带身份的Blazor服务器.Net 8 Cookie身份验证

为什么我的表单在绑定到对象时提交空值?

使用两个不同的枚举作为Switch语句中的CASE生成唯一值

如何在没有前缀和可选后缀的情况下获取Razor Page Handler方法名称?

在.NET核心项目中创建Startup.cs比在Program.cs中注册服务好吗?

如何将此方法参数化并使其更灵活?

如何通过寻找向量长度来优化两个循环?

如何使用MailKit删除邮箱?

如何在我的C#应用程序中设置带有reactjs前端的SignalR服务器?

当试图限制EF Select 的列时,如何避免重复代码?

带有可选参数的模拟方法返回意外的不同值,具体取决于可选的默认值

为什么ReadOnlySpan;T&>没有Slice(...)的重载接受Range实例的?

如何让游戏对象在切换场景时被销毁,但在开始新游戏时重新锁定

如何在C#控制台应用程序中获取用户输入并将其作为订单项目进行处理?

如何在.NET MAUI上在iOS和Mac之间共享代码?(no条件编译和无代码重复)

游戏对象走向不同的方向