代码之家  ›  专栏  ›  技术社区  ›  user366312

list<t>项目移除问题

  •  1
  • user366312  · 技术社区  · 15 年前

    不要害怕大量的代码。问题是一般性的。我只是提供了更好地理解问题的代码。

    我试图找出一种处理具有多对多关系的表的标准方法。我快做完了。在这里 Teacher Course 有m:m的关系。我的课程设计如下:

    教师 -班:

    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);//...
        }
    }
    

    课程 完全类似于 教师 一流的。映射类如下:

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

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

    我应该如何重构我的老师/课程班来实现这一点?

    也不例外。持久性代码没有问题。未删除项目。

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

    检查什么?

    5 回复  |  直到 15 年前
        1
  •  4
  •   Henk Holterman    15 年前

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

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


    拍摄:

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

    我怀疑CPP课程被加载了两次,内存中有两个该课程的实例。你的设计结果很糟糕。默认情况下,这两个实例将不相等,这就是为什么 Remove 不起作用。你可能超载 Equals , == GethashCode 但那是 not recommended for mutable types .
    你真正需要的是一个设计,对于一个给定的老师或课程,在内存中从来没有超过一个实例。

    重新评论:OO中的MXM关系如下:

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

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

        2
  •  3
  •   Foxfire    15 年前

    你想做什么?您的示例似乎希望构建一个在C中实现的关系数据库表。

    如果你想有一个面向对象的表现,那么就把整个课程老师班都取消。这与OO完全无关。

        3
  •  1
  •   Rubens Farias    15 年前

    看来你已经解决了这个问题,但是考虑一下下面的代码 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
    }
    
        4
  •  1
  •   Dylan Beattie    15 年前

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

    ADO.NET的DataTable和DataSet并没有真正提供对象关系映射功能;因为它们与基础数据库架构紧密耦合,所以当您真正想从教师和课程的角度进行思考时,它们会强制您从列、表和关系的角度进行思考。

    我真的建议你看看 Castle ActiveRecord 对于这个场景。它使用与示例相同的方法-static teacher.get()检索实例,myteacher.save()保存更改-但是您的示例缺少很多必要的复杂性,并且使用ORM框架将允许您忽略这种复杂性并专注于您自己的项目需求。

    这是 an example of many-many associations 从Castle ActiveRecord文档中,您可能会发现有帮助。

        5
  •  0
  •   o.k.w    15 年前

    在老师的课堂上进行添加和删除怎么样?

    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
    
    }