【问题标题】:How to handle a Many to Many Relationship in EFCore 3如何在 EFCore 3 中处理多对多关系
【发布时间】:2021-12-11 22:41:54
【问题描述】:

我已将我的数据库模型从现有的 .net Framework 解决方案迁移到 Core 3.1 解决方案。以前的框架使用数据库优先方法和 EDMX 文件来构建其 EF。 EFCore 没有数据库优先方法作为选项,但它们是一个脚手架工具,可以进行初始构建以开始。我已经做了脚手架,但是我的多对多关系出现了错误。字段的名称已更改,与当前问题无关的属性已被删除。为了解决这个问题,CollegeCourse 可以有很多学生,学生也可以有很多大学课程。

错误:无法确定“ICollection Student”类型的导航属性“CollegeClass.Students”表示的关系。手动配置关系,或使用“[NotMapped]”属性或使用“OnModelCreating”中的“EntityTypeBuilder.Ignore”忽略此属性。


public class CollegeClass
{
       [Key]
       public int Id{get;set;}
       public string CourseName {get;set;}
       [InverseProperty(nameof(Student.CollegeCourses))]
       public virtual ICollection<Student> Students{ get; set; } 
       [InverseProperty(nameof(CollegeCoursesToStudents.CollegeCourse))]
       public virtual ICollection<CollegeCoursesToStudents> CollegeCoursesToStudentss{ get; set; }
}
public class Student
{
        [Key]
        public int Id{get;set;}
        public string StudentName{get;set;}
        [InverseProperty(nameof(CollegeCourse.Students))]
        public virtual ICollection<CollegeCourse> CollegeCourses{ get; set; }
        [InverseProperty(nameof(CollegeCoursesToStudents.Student))]
        public virtual ICollection<CollegeCoursesToStudents> CollegeCoursesToStudentss{ get; set; }
}
public class CollegeCoursesToStudents
{
        [Key]
        public int CollegeCourseId{ get; set; }
        [Key]
        public int StudentId { get; set; }

        [ForeignKey(nameof(CollegeCourseId))]
        [InverseProperty("CollegeCoursesToStudentss")]
        public virtual CollegeCourse CollegeCourse{ get; set; }
        [ForeignKey(nameof(StudentId))]
        [InverseProperty("CollegeCoursesToStudentss")]
        public virtual Student Student { get; set; }
}

在我的模型构建课程中,我为 CollegeCoursesToStudents 实体提供了这个

           modelBuilder.Entity<RoutingRuleIdToOrderId>(entity =>
            {
                entity.HasKey(e => new { e.CollegeCourseId, e.StudentId });

                entity.HasOne(d => d.CollegeCourse)
                    .WithMany(p => p.CollegeCoursesToStudents)
                    .HasForeignKey(d => d.CollegeCourseId)
                    .OnDelete(DeleteBehavior.ClientSetNull)
                    .HasConstraintName("FK_CollegeCoursesToStudents_MerchantRoutingRules");

                entity.HasOne(d => d.Student)
                    .WithMany(p => p.CollegeCoursesToStudents)
                    .HasForeignKey(d => d.StudentId)
                    .HasConstraintName("FK_CollegeCoursesToStudents_Students");
            });

我查看了有关执行多对多的各种链接以及相关的错误消息。例如,此链接概述了类似的问题和解决方案,但似乎没有解决我的问题。

https://www.learnentityframeworkcore.com/configuration/many-to-many-relationship-configuration

【问题讨论】:

  • 您使用 EFCore 3.1 而不是 EFCore 5 或 EFCore 6 是否有原因?过去一年有很多重大改进。
  • @Dai 这最终将作为函数应用程序运行。目前,函数应用程序为框架选择提供了 3.1 或 6 的选择。 6的sdk还没有,2022还是很新的。我其实是从5.0开始的,然后才去部署一个测试受限功能版本,发现这个问题。
  • EF Core 6 for .NET 6 was released a few weeks ago,或者您指的是不同的 SDK?您仍然可以使用在 .NET Core 3.1 上运行的 EF Core 5。
  • @dai 根据此链接dotnet.microsoft.com/en-us/download/visual-studio-sdks,.NET6 不能作为 SDK 使用。当我尝试安装 EFcore 6 框架时,它需要 .net6。也许我错了。
  • 您是正确的,因为 EF Core 6 需要 .NET 6,而后者又需要 Visual Studio 2022 - 但是您对 EF Core 5 应该没有问题。

标签: c# ef-core-3.1


【解决方案1】:

您已经拥有多对多表,因此请从您的代码中删除此行。它将在 net 5+ 中工作,但您仅使用 3.1。

  [InverseProperty(nameof(Student.CollegeCourses))]
   public virtual ICollection<Student> Students{ get; set; } 

 [InverseProperty(nameof(CollegeCourse.Students))]
        public virtual ICollection<CollegeCourse> CollegeCourses{ get; set; }

并且由于您使用的是数据注释属性,因此您不需要流利的 api。尝试将它们从您的数据库上下文中删除

【讨论】:

  • 我个人并不依附于属性或fluent API。我的实际项目有 80 个实体,我需要在测试之前删除属性吗?或者我是否应该只为涉及此问题的 3 个实体这样做。
  • @DanScan 我对其他类一无所知,我说的是你发布的 fluent api。
【解决方案2】:

我的例子。我更喜欢 fluent api 而不是注解。

第 1 步。代码

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace College.Model
{
    public class CollegeClass
    {
        public int Id { get; set; }
        public string Name { get; set; } 

        //Navigation
        public ICollection<Enrollment> Enrollments { get; set; } = null!;
    }
    public class Student
    {
        public int Id { get; set; }
        public string Name { get; set; } 

        //Navigation
        public ICollection<Enrollment> Enrollments { get; set; } 
    }
    public class Enrollment
    {
        public int Id { get; set; }
        public int CollegeClassId { get; set; }
        public int StudentId { get; set; }

        public CollegeClass CollegeClass { get; set; } 
        public Student Student { get; set; } 
    }

    public class CollegeClassConfiguration : IEntityTypeConfiguration<CollegeClass>
    {
        public void Configure(EntityTypeBuilder<CollegeClass> builder)
        {
            builder.Property(e => e.Id).ValueGeneratedOnAdd();
            builder.Property(e => e.Name).HasMaxLength(64).IsUnicode().IsRequired();

            builder.HasKey(e => e.Id);
            builder.HasIndex(e => e.Name).IsUnique();
        }
    }

    public class StudentConfiguration : IEntityTypeConfiguration<Student>
    {
        public void Configure(EntityTypeBuilder<Student> builder)
        {
            builder.Property(e => e.Id).ValueGeneratedOnAdd();
            builder.Property(e => e.Name).HasMaxLength(64).IsUnicode().IsRequired();

            builder.HasKey(e => e.Id);
            builder.HasIndex(e => e.Name).IsUnique();
        }
    }

    public class EnrollmentConfiguration : IEntityTypeConfiguration<Enrollment>
    {
        public void Configure(EntityTypeBuilder<Enrollment> builder)
        {
            builder.Property(e => e.Id).ValueGeneratedOnAdd();
            builder.Property(e => e.CollegeClassId).IsRequired();
            builder.Property(e => e.StudentId).IsRequired();

            builder.HasKey(e => e.Id);
            builder.HasIndex(e => new { e.StudentId, e.CollegeClassId }).IsUnique();

            builder.HasOne(e => e.CollegeClass).WithMany(e => e.Enrollments).HasForeignKey(e => e.CollegeClassId);
            builder.HasOne(e => e.Student).WithMany(e => e.Enrollments).HasForeignKey(e => e.StudentId);
        }
    }

    public class CollegeContext: DbContext
    {
        public DbSet<CollegeClass> CollegeClasses { get; set; } 
        public DbSet<Student> Students { get; set; }
        public DbSet<Enrollment> Enrollments { get; set; }

        public CollegeContext(DbContextOptions<CollegeContext> options) : base(options)
        {
        }

        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);
            builder.ApplyConfiguration(new CollegeClassConfiguration());
            builder.ApplyConfiguration(new StudentConfiguration());
            builder.ApplyConfiguration(new EnrollmentConfiguration());
        }
    }
}

第 2 步。迁移
在 nuget 控制台中输入Add-Migration MyMigrationIdentifier

第 3 步。更新数据库
在 nuget 控制台中输入Update-Database

第 4 步。在 Sql 中检查结果
使用带有命令 Script-DbContext 的 nuget 控制台

CREATE TABLE [CollegeClasses] (
    [Id] int NOT NULL IDENTITY,
    [Name] nvarchar(64) NOT NULL,
    CONSTRAINT [PK_CollegeClasses] PRIMARY KEY ([Id])
);
GO


CREATE TABLE [Students] (
    [Id] int NOT NULL IDENTITY,
    [Name] nvarchar(64) NOT NULL,
    CONSTRAINT [PK_Students] PRIMARY KEY ([Id])
);
GO


CREATE TABLE [Enrollments] (
    [Id] int NOT NULL IDENTITY,
    [CollegeClassId] int NOT NULL,
    [StudentId] int NOT NULL,
    CONSTRAINT [PK_Enrollments] PRIMARY KEY ([Id]),
    CONSTRAINT [FK_Enrollments_CollegeClasses_CollegeClassId] FOREIGN KEY ([CollegeClassId]) REFERENCES [CollegeClasses] ([Id]) ON DELETE CASCADE,
    CONSTRAINT [FK_Enrollments_Students_StudentId] FOREIGN KEY ([StudentId]) REFERENCES [Students] ([Id]) ON DELETE CASCADE
);
GO


CREATE UNIQUE INDEX [IX_CollegeClasses_Name] ON [CollegeClasses] ([Name]);
GO


CREATE INDEX [IX_Enrollments_CollegeClassId] ON [Enrollments] ([CollegeClassId]);
GO


CREATE UNIQUE INDEX [IX_Enrollments_StudentId_CollegeClassId] ON [Enrollments] ([StudentId], [CollegeClassId]);
GO


CREATE UNIQUE INDEX [IX_Students_Name] ON [Students] ([Name]);
GO

参考文献

【讨论】:

    猜你喜欢
    • 2021-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-01
    • 2021-01-28
    • 1970-01-01
    • 1970-01-01
    • 2011-09-13
    相关资源
    最近更新 更多