1

不要害怕大量的代码。问题很普遍。我只是提供了代码以更好地理解问题。

我试图找出一种处理具有多对多关系的表的标准方法。我几乎完成了。这里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);//...
    }
}

Course绝对类似于Teacher- 类。并且映射类如下:

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();

这不起作用,因为它可能找不到匹配项或获取访问器正在返回只读列表。

我应该如何重构我的教师/课程 - 类来实现这一目标?

没有例外。持久性代码没有问题。项目不会被移除。

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

检查什么?

4

5 回答 5

4

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

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


拍摄:

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

我怀疑 cpp 课程被加载了两次,并且内存中有 2 个该课程的实例。你的设计的一个非常糟糕的后果。默认情况下,这两个实例不相等,这就是为什么Remove不起作用。您可以重载Equals==GethashCode建议对可变类型这样做。
您真正需要的是一种设计,对于给定的教师或课程,内存中永远不会存在超过 1 个实例。

重新评论:OO 中的 MxM 关系如下所示:

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

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

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

于 2009-10-18T11:03:48.257 回答
3

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

如果你想有一个面向对象的表示然后摆脱整个 CourseTeacher 类。这与 OO 完全无关。

于 2009-10-18T10:34:09.220 回答
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
}
于 2009-10-18T11:36:32.540 回答
1

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

ADO.NET 的 DataTable 和 DataSet 并没有真正提供对象关系映射功能;因为它们与底层数据库模式紧密耦合,所以当你真的想从教师和课程的角度思考时,它们会迫使你从列、表和关系的角度来思考。

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

这是Castle ActiveRecord 文档中的多对多关联示例,您可能会发现它很有帮助。

于 2009-10-18T11:48:43.397 回答
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

}
于 2009-10-18T10:45:32.280 回答