列表项目删除问题

发布于 2024-08-07 15:46:48 字数 2763 浏览 2 评论 0原文

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

我试图找到一种处理具有多对多关系的表的标准方法。我快完成了。这里TeacherCourse有M:M关系。我的课程设计如下:

Teacher - class:

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 - class 绝对相似。映射类如下:

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); 返回 false?

需要检查什么?

Don't be scared of the extensive code. The problem is general. I just provided the code to understand the problem better.

I am trying to find out a standard approach of manipulating tables with many-to-many relationships. And I am almost done. Here Teacher and Course have M:M relationship. I have designed my classes as follows:

Teacher - class:

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 is absolutely similar to Teacher - class. And the mapping class is as follows:

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){}
}

Now my problem is, this code is not working?

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

This is not working because it is not probably finding a match or get accessor is returning readonly List.

How should I refactor my Teacher/Course - class to achieve this?

No exception. No problem with persistence code. Items are not being removed.

why professorXyz.Items.Contains(cpp); is returning false?

What to check for?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

甜味超标? 2024-08-14 15:46:49

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

你的设计是非常(非常)相关的。这使得持久化到数据库变得更容易,但你没有合适的面向对象模型。也许您应该考虑在 DataSet 中使用 DataTable 并获得 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 = ...;
}

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

This is not a direct answer, but...

Your design is very (very) Relational. That makes persisting to a DB easier but you do not have a proper OO model. Maybe you should consider using DataTables in a DataSet and reap the benefits of the Relation class.


To take a shot:

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

I suspect that the cpp course is being loaded twice, and that there are 2 instances of that course in memory. A very bad consequence of your design. By default, those 2 instances will not be equal and that is why Remove does not work. You could overload Equals, == and GethashCode but that is not recommended for mutable types.
What you really need is a design where for a given Teacher or Course there never exists more than 1 instance in memory.

Re Comment: A MxM relation in OO looks like:

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

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

This will take a little more work to write to a DB but it solves a lot of other problems.

转身泪倾城 2024-08-14 15:46:49

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

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

What are you trying to do? Your sample looks like you want to build a relational database table implemented in C#.

If you want to have an OO representation then get rid of the entire CourseTeacher class. That has absolutely nothing to do with OO.

执着的年纪 2024-08-14 15:46:49

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

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
}

seems you already solved this problem, but consider following code where I overrode bool Equals; C# couldn't knew how to compare your new cpp instance with another instance in your List<Course>, so we need to tell it by creating a more specialized Equals method:

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
}
惟欲睡 2024-08-14 15:46:49

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

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

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

这是多对多关联的示例 Castle ActiveRecord 文档可能会对您有所帮助。

Henk is correct; your design is very, very relational. For this sort of scenario, though, you're better off focusing on behaviour in your objects, and using an object-relational mapping (ORM) tool to translate between your objects and your database.

ADO.NET's DataTable and DataSet don't really offer object-relational mapping capabilities; because they're so tightly coupled to the underlying database schema, they force you to think in terms of columns, tables and relations, when you really want to be thinking in terms of teachers and courses.

I would seriously recommend looking at Castle ActiveRecord for this scenario. It uses the same approach as your example - static Teacher.Get() to retrieve an instance, myTeacher.Save() to save your changes - but there's a LOT of necessary complexity that your example is missing, and using an ORM framework will allow you to ignore this complexity and focus on your own project's requirements.

Here's an example of many-many associations from the Castle ActiveRecord documentation that you may find helpful.

葬心 2024-08-14 15:46:49

添加和删​​除在教师班级中完成怎么样?

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

}

How about adding and removing done within the Teacher Class?

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

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文