【问题标题】:EF Core 3.1 Fluent APIEF Core 3.1 流畅的 API
【发布时间】:2021-04-22 23:45:40
【问题描述】:

我有两个实体:

审计类

public class Audit
{
  public string AuditId{get;set;}
  public int EmployeeId{get;set;}
  public virtual ModEmployee{get;set;}
}

员工类

public class Employee
{
  public int EmployeeId{get;set}
}

在加载 Set<Audit> 时,我希望填充 Audit 类的 Employee 属性。 这显然是一对多关系的情况,其中一个审计将有一个员工,但一个员工可以在多个审计中。

我的 Fluent API 如下所示:

protected override OnModelCreating(ModelBuilder modelBuilder)
{
  modelBuilder.Entity<Audit>()
 .HasOne(a=>a.ModEmployee)
 .WithMany()
 .HasForeignKey("EmployeeId");//a=>a.EmployeeId wont work.

}

一段时间以来,我一直在寻找解决方案,并从this answer 获取了一些信息,但它是针对一对一的。然后this resource 显示了一种方法,但这需要我在 Employee 类中有一个 Audits 集合。


我无法更改现有模型或添加注释,因为它们已被其他实体框架版本(非核心)使用。


目前我收到以下错误:

System.InvalidOperationException: '无法确定 由导航属性“Employee.ModEmployee”表示的关系 输入“员工”。要么手动配置关系,要么忽略 此属性使用“[NotMapped]”属性或使用 'OnModelCreating'中的'EntityTypeBuilder.Ignore'。'

如果我在 Audit 的构建器上添加忽略方法,错误就会消失,如下所示:.Ignore(a=&gt;a.ModEmployee) 但我不会在 Audit 中获取实体对象。任何帮助将不胜感激。我在 EFCore 3.1.10 上。谢谢阅读。 任何帮助将不胜感激。


【问题讨论】:

  • 错误消息中显示的是“Employee.ModEmployee”而不是“Audit.ModEmployee”,这很尴尬。您是否尝试删除 .HasForeignKey("EmployeeId")?
  • @heringer 我没有,我认为它只会加载 EmployeeId 而不会对 ModEmplyee 做任何事情。但我看你有一点,会试一试。感谢您的评论!
  • 我测试了您的示例,它在 EF Core 3.1.10 和 EF Core 5 中的工作方式与您的 OnModelCreating 配置一样。问题一定出在其他地方。
  • 仅供参考,下一个设置 modelBuilder.Entity&lt;Audit&gt;().HasOne(a =&gt; a.ModEmployee).WithMany().HasForeignKey(a =&gt; a.EmployeeId); 对我来说很好。

标签: c# .net entity-framework asp.net-core-3.1 ef-core-3.1


【解决方案1】:

尝试在Audit 类中将您的类型从int 更改为Employee。 应该可以正常工作,因为这是在 fluent API 中关联外键的正确方法。

PS:FK 归属字符串应与Employee 内的完全相同,这已经发生了。

【讨论】:

    【解决方案2】:

    我最近遇到了同样的问题。这对我有用:

    方法一: 使用对 Audit 集合的引用定义您的 Employee 类:

    public class Employee
    {
      public int EmployeeId { get; set }
      public virtual ICollection<Audit> Audits { get; set; }
    }
    

    然后在您的模型构建器中以这种方式定义关系:

    builder.Entity<Audit>().HasOne(e => e.ModEmployee).WithMany(ae => ae.Audits).HasForeignKey(k => k.EmployeeId);
    

    你总是需要在每个类中定义集合。

    编辑!!

    方法二:

    public class Audit
    {
      public string AuditId{get;set;}
      public Employee Employee { get; set; }
    }
    

    我知道这需要你编辑你的课程,但相信我,这会让事情变得更容易。

    【讨论】:

    • 感谢您的回答,但就像我说的,我无法更改模型或添加注释,因为这些类在 EF6 上运行良好。我正在为 EFCore 迁移编写并行流程,因此必须使用相同的模型。
    • 恐怕您不能这样做,ICollection 不会更改数据库中的任何内容,但 EFCore 将需要定义“本地”存储此检索的数据库行的位置。我在同一个项目中使用了 EF6 和 EFCore,但我对这个 ICollection 接口没有任何问题。
    • 但是这个现有的设置如何在 EF6 中使用 IsRequired(...).WithMany().HasForeignKey(...) 方法!
    • 您可以只使用 EFCore 自动绑定。使用对 Employee 的对象引用定义审计类,这应该会自动在您的数据库中添加一个外键。我将编辑我的答案,以便您正确查看
    【解决方案3】:

    如果您无法修改模型类。

    您可以简单地在您的上下文中添加一个检索审计的方法。

    using Microsoft.EntityFrameworkCore;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace EFCoreFluentApi1.Context
    {
        public class MyContext : DbContext
        {
            public DbSet<Audit> Audit { get; set; }
            public DbSet<Employee> Employee { get; set; }
    
            public MyContext(DbContextOptions options) : base(options)
            {
            }
    
            protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
            {
                base.OnConfiguring(optionsBuilder);
    
            }
            protected override void OnModelCreating(ModelBuilder builder)
            {
                base.OnModelCreating(builder);
    
                builder.Entity<Employee>().HasKey(e => e.EmployeeId);
                builder.Entity<Employee>().Property(e => e.EmployeeId);
    
                builder.Entity<Audit>().HasKey(e => e.AuditId);
                builder.Entity<Audit>().Property(e => e.AuditId);
                builder.Entity<Audit>().HasOne(e => e.ModEmployee).WithMany().HasForeignKey(e => e.EmployeeId);
    
                builder.Entity<Employee>().HasData(new Employee[]
                {
                    new Employee{ EmployeeId = 1 },
                    new Employee{ EmployeeId = 2 },
                    new Employee{ EmployeeId = 3 },
                    new Employee{ EmployeeId = 4 }
                });
    
                builder.Entity<Audit>().HasData(
                    new Audit[]
                    {
                        new Audit
                        {
                            AuditId = "Audit1",
                            EmployeeId = 1
                        },
                        new Audit
                        {
                            AuditId = "Audit2",
                            EmployeeId = 1
                        },
                        new Audit
                        {
                            AuditId = "Audit3",
                            EmployeeId = 1
                        },
                        new Audit
                        {
                            AuditId = "Audit4",
                            EmployeeId = 2
                        },
                        new Audit
                        {
                            AuditId = "Audit5",
                            EmployeeId = 3
                        },
                        new Audit
                        {
                            AuditId = "Audit6",
                            EmployeeId = 3
                        },
                        new Audit
                        {
                            AuditId = "Audit7",
                            EmployeeId = 4
                        },
                        new Audit
                        {
                            AuditId = "Audit8",
                            EmployeeId = 4
                        },
                        new Audit
                        {
                            AuditId = "Audit9",
                            EmployeeId = 4
                        },
                        new Audit
                        {
                            AuditId = "Audit10",
                            EmployeeId = 4
                        }
    
                    });
            }
    
            public ICollection<Audit> GetAudits(int employeeId)
            {
                return Audit.Where(e => e.EmployeeId == employeeId).ToList();
            }
    
        }
    }
    
    

    如果需要填充 ModEmployee,可以使用 Include 方法。

    using EFCoreFluentApi1.Context;
    using Microsoft.EntityFrameworkCore;
    using Microsoft.Extensions.Configuration;
    using System;
    using System.IO;
    using System.Linq;
    using System.Text.Json;
    
    namespace EFCoreFluentApi1
    {
        class Program
        {
            static void Main(string[] args)
            {
                IConfiguration configuration = new ConfigurationBuilder().
                        SetBasePath(Directory.GetCurrentDirectory())
                        .AddJsonFile("appsettings.json", false, true)
                        .Build();
    
    
                DbContextOptions options = new DbContextOptionsBuilder<MyContext>()
                    .UseSqlServer(configuration.GetConnectionString("MyConnectionString"))
                    .EnableSensitiveDataLogging(true).Options;
    
                using (var context = new MyContext(options))
                {
                    var result = context.Audit.Include(e => e.ModEmployee).ToList(); //ModEmployee is populated 
                    //var result = context.Audit.ToList(); //ModEmployee = null
                    foreach (var value in result)
                    {
                        Console.WriteLine($"█ Audit: {value.AuditId}");
                        Console.WriteLine(JsonSerializer.Serialize(value));
                        Console.WriteLine();
                    }
                    Console.ReadLine();
                }
            }
        }
    }
    
    

    https://github.com/JomaStackOverflowAnswers/EFCoreFluentApi1 中查看我的示例 这个项目是&lt;TargetFramework&gt;netcoreapp3.1&lt;/TargetFramework&gt;

    检查 IsRequired 显式 https://docs.microsoft.com/en-us/ef/core/modeling/entity-properties?tabs=fluent-api%2Cwithout-nrt#explicit-configuration

    【讨论】:

    • 感谢您的回答。这是 EFCore 3.1.10 而不是 EF。我问是因为 afaik,ISRequired() 不适用于 EFCore。
    • 检查示例的 URI。更新答案。
    • 我的错,它的 HasRequired 而不是 IsRequired。需要一个妈妈来消化你的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-11
    • 2015-07-06
    • 1970-01-01
    • 2021-09-05
    相关资源
    最近更新 更多