列出<t>项目删除问题</t>

时间:2009-10-18 10:19:10

标签: c# many-to-many relational-database

不要害怕广泛的代码。问题很普遍。我刚刚提供了代码来更好地理解这个问题。

我试图找出一种操纵具有多对多关系的表的标准方法。而且我差不多完成了。此处TeacherCourse具有M:M关系。我按如下方式设计了我的课程:

Teacher - 课程:

public class Teacher
{
    public int ID{get;set;}
    public string TeacherName{get;set;}
    private List<Course> _items = null;
    public List<Course> Items
    {
        get 
        {   if (_items == null) {_items = Course.GetCoursesByTeacherID(_ID);}
            return _items;
        }
        set {_items = value;}
    }
    public int Save() 
    {   //...
        CourseTeacher.DeleteCoursesByTeacherID(tc, id);
        CourseTeacher.SaveCoursesWithTeacherID(tc, id, this.Items);
        //...
    }
    public bool Update()
    {   //...
        CourseTeacher.DeleteCoursesByTeacherID(tc, this.ID);
        CourseTeacher.SaveCoursesWithTeacherID(tc, this.ID, this.Items);
        //...
    }
    public static Teacher Get(int id)
    {   //...
        item.Items = CourseTeacher.GetCoursesByTeacherID(tc, item.ID);//...
    }
    public static List<Teacher> Get()
    {   //...
        items[i].Items = CourseTeacher.GetCoursesByTeacherID(tc, items[i].ID);//...
    }
    public static List<Teacher> GetTeachersByCourseID(int id)
    {   //...
        items = CourseTeacher.GetTeachersByCourseID(tc, id);//...
    }
    public bool Delete()
    {   //...
        CourseTeacher.DeleteCoursesByTeacherID(tc, this.ID);//...
    }
}

CourseTeacher - 类完全相似。映射类如下:

public class CourseTeacher
{
    public int CourseID{get;set;}
    public int TeacherID{get;set;}  
    public static void SaveCoursesWithTeacherID(TransactionContext tc, int teacherID, List<Course> items){}
    public static void SaveTeachersWithCourseID(TransactionContext tc, int courseID, List<Teacher> items){}
    private void Save(TransactionContext tc){}
    public static void DeleteCoursesByTeacherID(TransactionContext tc, int teacherID){}
    public static void DeleteTeachersByCourseID(TransactionContext tc, int courseID){}
    public static List<Teacher> GetTeachersByCourseID(TransactionContext tc, int courseID){}
    public static List<Course> GetCoursesByTeacherID(TransactionContext tc, int teacherID){}
}

现在我的问题是,这段代码无效?

Teacher professorXyz = Teacher.Get(2);                        
Course cpp = Course.Get(3);
Course java = Course.Get(2);
professorXyz.Items.Remove(cpp);
professorXyz.Items.Remove(java);
professorXyz.Update();

这不起作用,因为它可能找不到匹配或者访问者正在返回只读List。

我应该如何重构我的老师/课程班来实现这个目标?

没有例外。持久性代码没问题。物品未被移除。

为什么professorXyz.Items.Contains(cpp);返回false?

要检查什么?

5 个答案:

答案 0 :(得分:4)

这不是一个直接的答案,但是......

你的设计非常(非常)关系。这使得持久化到数据库更容易,但您没有适当的OO模型。也许你应该考虑在DataSet中使用DataTables并获得Relation类的好处。


拍摄:

Teacher professorXyz = Teacher.Get(2);                        
Course cpp = Course.Get(3);

我怀疑cpp课程被加载两次,并且内存中有2个该课程的实例。你设计的一个非常糟糕的后果。默认情况下,这两个实例不相等,这就是Remove不起作用的原因。您可以重载Equals==GethashCode,但这是not recommended for mutable types
你真正需要的是一种设计,对于给定的教师或课程,在内存中永远不会存在多于1个实例。

评论:OO中的MxM关系如下:

class Teacher
{
   public readonly List<Course> Courses = ...;
}

class Course
{
   public readonly List<Teacher> Teachers = ...;
}

这将需要更多的工作来写入数据库,但它解决了许多其他问题。

答案 1 :(得分:3)

你想做什么?您的示例看起来像是要构建一个用C#实现的关系数据库表。

如果你想要一个OO表示,那么就去掉整个CourseTeacher类。这与OO完全无关。

答案 2 :(得分:1)

您似乎已经解决了这个问题,但请考虑使用以下代码覆盖bool Equals; C#无法知道如何将新的cpp实例与List<Course>中的其他实例进行比较,因此我们需要通过创建更专业的Equals方法来告诉它:

class Teacher
{
    private List<Course> items = new List<Course>();

    public int ID { get; set; }
    public List<Course> Items { get { return items; } }
}

class Course
{
    public int ID { get; set; }

    public override int GetHashCode()       { return base.GetHashCode(); }
    public override bool Equals(object obj) { return Equals(obj as Course); }
    public bool Equals(Course another)
    {
        return another != null && this.ID.Equals(another.ID);
    }
} 

static void Main(string[] args)
{
    Teacher teacher = new Teacher { ID = 2 };
    teacher.Items.AddRange(
        new Course[] { 
            new Course{ ID = 2 },       // java
            new Course{ ID = 3 } });    // cpp

    Course cpp = new Course { ID = 3 }; // previous problem: another instance
    teacher.Items.Contains(cpp);        // now returns true
    teacher.Items.Remove(cpp);          // now returns true
}

答案 3 :(得分:1)

亨克是对的;你的设计是非常非常关系的。但是,对于这种情况,您最好关注对象中的行为,并使用对象关系映射(ORM)工具在对象和数据库之间进行转换。

ADO.NET的DataTable和DataSet并不真正提供对象关系映射功能;因为它们与底层数据库模式紧密耦合,当你真正想要在教师和课程方面进行思考时,它们迫使你在列,表和关系方面进行思考。

我会认真推荐在这种情况下查看Castle ActiveRecord。它使用与您的示例相同的方法 - 静态Teacher.Get()来检索实例,myTeacher.Save()来保存您的更改 - 但是您的示例缺少很多必要的复杂性,并且使用ORM框架将允许你要忽略这种复杂性,关注自己项目的要求。

以下是Castle ActiveRecord文档中的an example of many-many associations,您可能会觉得有用。

答案 4 :(得分:0)

如何在教师班内添加和删除?

public class Teacher
{
        //.... Original implementations
    public bool AddCourse(Course course) {
        if(_items.Contains(course)) return false;

        _items.Add(course);
        return true;
    }

        // similarly for remove course

}