I have the Course
entity that holds a collection of Students
, and they are in a Many-to-Many relationship, as per tutorial
Course class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Library
{
public class Course
{
public Course()
{
this.Students = new HashSet<Student>();
}
public string CourseId { get; set; }
public string CourseName { get; set; }
public string Department {get; set;}
public virtual ICollection<Student> Students { get; set; }
}
}
Student class
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace Library
{
public class Student
{
public Student()
{
this.Courses = new HashSet<Course>();
}
public string StudentId { get; set; }
[Required]
public string StudentName { get; set; }
public int Age { get; set; }
public virtual ICollection<Course> Courses { get; set; }
}
}
My method (azure function)
[FunctionName("UpdateCourse")]
public async Task<IActionResult> UpdateCourse(
[HttpTrigger(AuthorizationLevel.Anonymous, "put", Route = "courses/{CourseId}")]
HttpRequest req,
ILogger log, string CourseId) {
var course = await _context.Courses.FindAsync(CourseId);
// course.Students.Clear();
foreach (var item in course.Students)
{
course.Students.Remove(item);
}
_context.Update(course);
await _context.SaveChangesAsync();
return new OkObjectResult(removeSelfReference(course));
}
EDIT 1:
Here are parts of my code-first migration files for the join table CourseStudent
20220415034607_M1.cs:
migrationBuilder.CreateTable(
name: "CourseStudent",
columns: table => new
{
CoursesCourseId = table.Column<string>(type: "nvarchar(450)", nullable: false),
StudentsStudentId = table.Column<string>(type: "nvarchar(450)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_CourseStudent", x => new { x.CoursesCourseId, x.StudentsStudentId });
table.ForeignKey(
name: "FK_CourseStudent_Courses_CoursesCourseId",
column: x => x.CoursesCourseId,
principalTable: "Courses",
principalColumn: "CourseId",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_CourseStudent_Students_StudentsStudentId",
column: x => x.StudentsStudentId,
principalTable: "Students",
principalColumn: "StudentId",
onDelete: ReferentialAction.Cascade);
});
20220415034607_M1.Designer.cs:
modelBuilder.Entity("CourseStudent", b =>
{
b.HasOne("Library.Course", null)
.WithMany()
.HasForeignKey("CoursesCourseId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Library.Student", null)
.WithMany()
.HasForeignKey("StudentsStudentId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
CodePudding user response:
Did you verify that your course is lazy loading students? If lazy loading is disabled then course.Students will be empty. When modifying the collection of students you should be eager-loading it regardless:
var course = context.Courses
.Include(x => x.Students)
.Single(x => x.CourseId == courseId);
From there you should be able to use:
course.Students.Clear();
since Course.Students will be a proxy that EF recognizes and the Clear method will mark all entries for removal. With many-to-many relationships you may need to dis-associate the course from each of the students:
var course = context.Courses
.Include(x => x.Students)
.Single(x => x.CourseId == courseId);
foreach(var student in course.Students)
student.Courses.Remove(course);
course.Students.Clear();
context.SaveChanges();
to be sure that the references are removed in the event that any of the students might be marked as modified.
Lastly, with tracked entities, just call SaveChanges()
rather than calling Update
. Update
is for untracked/detached entities.