Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delete/Update Many to Many Entity Framework. Cannot get it to work

I m using EF4 and having problems with many to many update and delete of item. I am happy with the insert but update and delete cannot figure it out.

Suppose I have 3 tables and 3 dto classes that matches

  1. ClassRoom Table

       ClassID-ClassName 
    
  2. Student Table

       StudentID-StudentName
    
  3. StudentClass Table

       StudentID-ClassID
    
    
    ///Happy all works I am using existing students to populate the class. Fine.
    private void InsertClassRoom(ClassRoomDto classRoomDto)
    {
        using (var ctx = new TrainingContext())
        {
            //Convert dto to Entity
            var classRoomEntity = new ClassRoom { ClassID = classRoomDto.ClassId, ClassName = classRoomDto.ClassName };
            foreach (var studentInClass in classRoomDto.Students)
            {
                Student student = ctx.Students.Where(x => x.StudentID == studentInClass.StudentId).SingleOrDefault();
                classRoomEntity.Students.Add(student);
            }
            ctx.AddToClassRooms(classRoomEntity);
            ctx.SaveChanges();
        }
    }
    

But I have 2 scenarios that cannot figure out what to do.

  1. Update the classroom Name
  2. Add 1 student
  3. Update the name on 1 student

Delete a student from class.
How do I do it?

This is my attempt on update:

private void UpdateClassRoom(ClassRoomDto classRoomDto)
{
    using (var ctx = new TrainingContext())
    {
        var classRoomEntity = new ClassRoom { ClassID = classRoomDto.ClassId, ClassName = classRoomDto.ClassName };
        foreach (var studentDto in classRoomDto.Students)
        {
            if (studentDto.StudentId == 0)
            {
                //it's a new student add it to the classroom
                Student student = new Student { StudentID = studentDto.StudentId, StudentName = studentDto.StudentName };
                classRoomEntity.Students.Add(student);
            }
            else
            {
                //Alter name of the student
                Student student = ctx.Students.Where(x => x.StudentID == studentDto.StudentId).SingleOrDefault();
                //update name
                student.StudentName = studentDto.StudentName;
                //? what do I do finish this attach or ???
           }
        }
        ctx.AddToClassRooms(classRoomEntity);
        ctx.SaveChanges();
    }
}

public void DeleteStudent(ClassRoomDto classRoomDto)
{
    using (var ctx = new TrainingContext())
    {
        //lost on how to delete a student in  many to many 
    }
}
like image 238
user9969 Avatar asked Nov 23 '10 20:11

user9969


1 Answers

First of all, I assume that you know that the classroom already exists in the database. The simplest approach is to query for it first. The reason you actually get a new ClassRoom entry inserted is that you use ctx.AddToClassRooms(classRoomEntry). This attaches the entity to the context and sets the EntityState to Added.

private void UpdateClassRoom(ClassRoomDto classRoomDto)
{
    using (var ctx = new TrainingContext())
    {
        ClassRoom classRoomEntity = ctx.
                                    ClassRooms.
                                    Include("Students").
                                    Single(c => c.ClassID == classRoomDto.ClassId);
        classRoomEntity.ClassName = classRoomDto.ClassName;

        foreach (var studentDto in classRoomDto.Students)
        {
            if (studentDto.StudentId == 0)
            {
                // it's a new student add it to the classroom
                Student student = new Student
                                      {
                                          StudentID = studentDto.StudentId,
                                          StudentName = studentDto.StudentName
                                      };
                classRoomEntity.Students.Add(student);
            }
            else
            {
                // Student exists in the DB, but you don't know whether it's 
                // already part of the student collection for the classroom
                Student student = classRoomEntity.
                                  Students.
                                  FirstOrDefault(s => s.StudentID == studentDto.StudentId);

                if (student == null)
                {
                    // this student is not in the class, fetch it from the DB
                    // and add to the classroom
                    student = ctx.
                              Students.
                              SingleOrDefault(s => s.StudentID == studentDto.StudentId)

                    classRoomEntity.Students.Add(student);
                }

                // Update name
                student.StudentName = studentDto.StudentName;
                // Since student is now part of the classroom student collection
                // and classroom IS attached => student is also attached
            }
        }

        ctx.SaveChanges();
    }
}

In order to delete a student from thr class, you need to simply remove it from the collection (but DON'T call ctx.DeleteObject(), since that will remove the student from the DB. In your case, the code above will not take care of this, since it only adds new students. Instead of matching all the students that are in the database, but not in your DTO, you could take a simpler approach. Clear the list first and then add the students:

private void UpdateClassRoom(ClassRoomDto classRoomDto)
{
    using (var ctx = new TrainingContext())
    {
        ClassRoom classRoomEntity = ctx.
                                    ClassRooms.
                                    Include("Students").
                                    Single(c => c.ClassID == classRoomDto.ClassId);
        classRoomEntity.ClassName = classRoomDto.ClassName;
        classRoomEntity.Students.Clear();

        foreach (var studentDto in classRoomDto.Students)
        {
            Student student;
            if (studentDto.StudentId == 0)
            {
                // it's a new student add it to the classroom
                student = new Student
                              {
                                  StudentID = studentDto.StudentId,
                                  StudentName = studentDto.StudentName
                              };
            }
            else
            {
                student = ctx.
                          Students.
                          SingleOrDefault(s => s.StudentID == studentDto.StudentId)

                // Update name
                student.StudentName = studentDto.StudentName;
            }

            classRoomEntity.Students.Add(student);
        }

        ctx.SaveChanges();
    }
}

This is probably the approach you are looking for. I specifically wrote up the first code snippet to show you the different cases of how to deal with new and existing entities, but it's the second one (simpler) approach that is more correct. Hope this helps.

like image 191
Yakimych Avatar answered Dec 31 '22 20:12

Yakimych