尝试从EF CodeFirst更新对象时,多个表中的重复条目

时间:2015-04-16 16:35:32

标签: c# .net linq entity-framework

以下是我的两个模型类学生和课程

public class Student
{
    private readonly IStudentOps _studentOps;

    public Student(IStudentOps studentOps)
    {
        _studentOps = studentOps;
    }
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime BirthDate { get; set; }

    public Student()
    {
        Courses = new List<Course>();
    }

    public virtual IList<Course> Courses { get; set; }

    public bool Enrol(Student student)
    {
        return _studentOps.EnrolOrUpdate(student);
    }

    public IEnumerable<Course> SeeCourses()
    {
        return _studentOps.SeeCourses();
    }
}


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

    public virtual IList<Student> Students { get; set; }
}

这是我的学生班级界面和服务

public interface IStudentOps
{
    bool EnrolOrUpdate(Student student);
    IEnumerable<Course> SeeCourses();
}


public class StudentOps : IStudentOps
{

    public bool EnrolOrUpdate(Student student)
    {
        using (var context = new StudentContext())
        {
            if (student.Id == 0)
            {
                context.Students.Add(student);
                context.SaveChanges();
                return true;
            }

            var tempStudent = context.Students.FirstOrDefault(x => x.Id == student.Id);

            // ReSharper disable once InvertIf
            if (tempStudent == null) return false;
            context.Students.Attach(tempStudent);
            tempStudent.Id = student.Id;
            tempStudent.Name = student.Name;
            tempStudent.BirthDate = student.BirthDate;
            tempStudent.Courses = student.Courses;
            context.Entry(tempStudent).State = EntityState.Modified;
            context.SaveChanges();
            return true;
        }
    }

    public IEnumerable<Course> SeeCourses()
    {
        return new List<Course>() { new Course() { Name = "Social" }, new Course() { Name = "Science" } };
    }
}

Context类

class StudentContext : DbContext
{
    public StudentContext() : 
        base("Name=StudentConn")
    {

    }
    public DbSet<Student> Students { get; set; }
    public DbSet<Course> Courses { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Student> ().HasMany(c=>c.Courses).WithMany(x=>x.Students)
            .Map(
                m =>
                {
                    m.MapLeftKey("StudentId");
                    m.MapRightKey("CourseId");
                    m.ToTable("Student_Course");
                });

    }
}

数据库中的数据

学生(表)
Id名称BirthDate
21佩德罗2015-04-16 16:12:49.270
22 John 2015-04-14 16:12:49.270
23 Shiv 2015-04-16 16:13:45.240

课程(表)
身份证号码 26科学 27 Grographic
28 TestCourse
29 NULL

Student_Course(表)
  StudentId CourseId
  23 28
  23 29

使用StudentOps表中的代码,我正在尝试更新名为Shiv的学生,使其具有课程26(科学)和27(Grography)而不是28(TestCourse)和29(NUll)(在许多表中)Student_Course。但每次我这样做,它会在表中插入重复的条目,而不是更新它。从代码更新Student_Course表的最佳方法是什么?有人帮忙吗?提前致谢

2 个答案:

答案 0 :(得分:1)

您应该能够清除tempStudent.Courses集合并从student.Courses重新添加集合,但如果最终结束,您可能需要先使用student.Courses从数据库中获取它们复制课程条目。

顺便说一句,tempStudent应该只是通过获取它来附加到上下文中,当你更改属性时,它应该已被标记为已修改。除非您已关闭跟踪功能?

此外,您不需要设置其Id,只是用它来获取它。

答案 1 :(得分:1)

更新多对多关系中的实体是EF,您需要执行以下操作:

  1. 将实体附加到上下文
  2. 确保您要更改的集合已加载
  3. 确保作为跟踪实体加载。
  4. 致电EF .SaveChanges()保存更改。
  5. 在你的情况下,你应该做这样的事情:

    public bool EnrolOrUpdate(Student student)
        {
            using (var context = new StudentContext())
            {
                if (student.Id == 0)
                {
                    context.Students.Add(student);
                    context.SaveChanges();
                    return true;
                }
    
                var tempStudent = context.Students.FirstOrDefault(x => x.Id == student.Id);
    
                // ReSharper disable once InvertIf
                if (tempStudent == null) return false;
                context.Students.Attach(tempStudent);
                tempStudent.Id = student.Id;
                tempStudent.Name = student.Name;
                tempStudent.BirthDate = student.BirthDate;
                tempStudent.Courses = student.Courses;
                Context.Entry(tempStudent).Collection(p => p.Students).Load();
                context.Entry(tempStudent).State = EntityState.Modified;
                context.SaveChanges();
                return true;
            }
        }