1


1

リスト<T>項目の削除の問題

大規模なコードを怖がってはいけません。 問題は一般的です。 問題をよりよく理解するためのコードを提供しました。

多対多の関係を持つテーブルを操作する標準的な方法を見つけようとしています。 そして私はもう終わりです。 ここで「先生」と「コース」はM:Mの関係にあります。 私は自分のクラスを次のように設計しました。

先生 - クラス:

public class Teacher
{
    public int ID{get;set;}
    public string TeacherName{get;set;}
    private List _items = null;
    public List 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 Get()
    {   //...
        items[i].Items = CourseTeacher.GetCoursesByTeacherID(tc, items[i].ID);//...
    }
    public static List 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 items){}
    public static void SaveTeachersWithCourseID(TransactionContext tc, int courseID, List 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 GetTeachersByCourseID(TransactionContext tc, int courseID){}
    public static List 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アクセサがreadonlyのListを返していないため、うまくいきません。

これを達成するためにどのように私は私の先生/コース - クラスをリファクタリングすべきですか?

例外なし。 永続化コードに問題はありません。 アイテムは削除されていません。

なぜ `professorXyz.Items.Contains(cpp);`がfalseを返すのですか?

何を確認しますか?

5 Answer


4


これは直接的な答えではありませんが、…​

あなたのデザインはとても(とても)リレーショナルです。 これにより、データベースへの永続化が容易になりますが、適切なオブジェクト指向モデルがありません。 たぶんあなたはDataSetの中でDataTableを使うことを考慮し、Relationクラスの恩恵を受けるべきです。

'' '' '

撮影するには:

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

私は、cppコースが2回ロードされていること、そしてそのコースのインスタンスが2つメモリ内にあることを疑っています。 あなたのデザインの非常に悪い結果。 デフォルトでは、これら2つのインスタンスは等しくありません、そしてそれが `Remove`が働かない理由です。 Equals、==、GethashCodeをオーバーロードすることができますが、それはhttp://msdn.microsoft.com/en-us/library/ms173147%28VS.80%29.aspx[_not_可変長の型に対して推奨されていません] 。 あなたが本当に必要としているのは、与えられた教師やコースに対して、メモリ内に2つ以上のインスタンスが存在しないようなデザインです。

再コメント:オブジェクト指向におけるMxMの関係は、

class Teacher
{
   public readonly List Courses = ...;
}

class Course
{
   public readonly List Teachers = ...;
}

これはDBへの書き込みにもう少し手間がかかりますが、他の多くの問題を解決します。


3


あなたは何をしようとしているのですか? サンプルは、C#で実装されたリレーショナルデータベーステーブルを構築したいようです。

あなたがオブジェクト指向表現を持ちたいのであれば、CourseTeacherクラス全体を取り除きます。 それはオブジェクト指向とはまったく関係ありません。


1


あなたはすでにこの問題を解決しているようですが、私が bool Equals`を上書きしたところで以下のコードを検討してください。 C#はあなたの新しい `cpp`インスタンスをあなたの List`の中の別のインスタンスと比較する方法を知ることができなかったので、もっと特別な `Equals`メソッドを作ることによってそれを伝える必要があります:

class Teacher
{
    private List items = new List();

    public int ID { get; set; }
    public List 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
}


1


ヘンクは正しいです。あなたのデザインはとても、とてもリレーショナルです。 ただし、このようなシナリオでは、オブジェクトの動作に焦点を当て、オブジェクトとデータベース間の変換にオブジェクトリレーショナルマッピング(ORM)ツールを使用することをお勧めします。

ADO.NETのDataTableとDataSetは、実際にはオブジェクトリレーショナルマッピング機能を提供しません。基礎となるデータベーススキーマと非常に密接に結び付いているため、教師、コースの観点から本当に考えたい場合は、列、テーブル、およびリレーションの観点から考えることを強いられます。

私は真剣にこのシナリオのためにhttp://www.castleproject.org/activerecord / index.html [Cast ActiveRecord]を見ることをお勧めします。 それはあなたの例と同じアプローチを使います - インスタンスを取得するためのstatic Teacher.Get()、あなたの変更を保存するためのmyTeacher.Save() - しかしあなたの例が欠けている必要な複雑さのLOTがあります。あなたはこの複雑さを無視してあなた自身のプロジェクトの要求に集中するべきです。

Castle ActiveRecordのドキュメントのhttp://www.castleproject.org/activerecord/documentation/trunk / usersguide /relations /hasandbelongs.html [多対多関連の例]は、役に立つことがあります。


0


先生クラス内で行われた追加と削除はどうですか?

パブリッククラスの先生{// .... オリジナルの実装public bool AddCourse(Course course){if(_items.Contains(course))はfalseを返します。

_items.Add(コース); trueを返します。 }

//削除コースも同様

}