不要害怕广泛的代码。问题很普遍。我刚刚提供了代码来更好地理解这个问题。
我试图找出一种操纵具有多对多关系的表的标准方法。而且我差不多完成了。此处Teacher
和Course
具有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();
这不起作用,因为它可能找不到匹配或者访问者正在返回只读List。
我应该如何重构我的老师/课程班来实现这个目标?
没有例外。持久性代码没问题。物品未被移除。
为什么professorXyz.Items.Contains(cpp);
返回false?
要检查什么?
答案 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
}