2

私はc#を初めて使用し、GenericsとEntityFrameworkと少し混同しています。データベースに2つのテーブルがあり、EntityFrameworkを使用してコードで取得します。私のaspxページには、ユーザーが選択したテーブルに基づいてデータを入力するグリッドがあります。

将来的にはさらに多くのテーブルがあります。そこで、データグリッドのソースリストを取得するためのファクトリパターンを作成したいと思いました。私は非常に混乱しているので、それを機能させることができません。

これがBaseClassと2つの子クラスの私のコードです。

static class Factory
{
    public static ReportBase GetReport(string name)
    {
        switch (name)
        {
            case "Child1":
                return new Child1();
            case "Child2":
                return new Child1();
            default:
                return null;
        }
    }
}

//Base Class 
class ReportBase<T>
{
    public List<T> _list;
    public abstract void Load();
    public abstract List<T> Filter(DateTime statrtDate, DateTime endDate);
}

//Child 1
class Child1 : ReportBase
{
    public List<GetChild1> _list;
    public Child1(){}

    public override void Load()
    {
        //GetChild1 is the name of database table
        var info = from p in Context.GetChild1 select p;
        _list = info.ToList();
    }

    public List<GetChild1> Filter(DateTime startDate, DateTime endDate)
    {
        var filteredValues = from p in _list where p.UploadedDate <= startDate select p;
        return filteredValues.ToList();
    }
}

//Child 2
class Child2 : ReportBase
{
    public List<GetChild2> _list;
    public Child2() { }

    public override void Load()
    {
        //GetChild2 is the name of database table
        return  (from p in Context.GetChild2 select p).ToList();
    }

    public List<GetChild2> Filter(DateTime startDate, DateTime endDate)
    {
        return  (from p in _list where p.UploadedDate <= startDate select p).ToList();
    }
} 

誰かがそれに応じてコードを修正できますか?ここでジェネリックを使用する必要がありますか?BaseClassで使用してみましたが、それに応じて子クラスを修正する必要があるため、正しく機能しません。これについては、手がかりがありません。

4

2 に答える 2

0

各エンティティタイプ(またはテーブル)を表示する方法を定義するためのジェネリックは、間違ったアプローチです。

代わりに、MVVMやMVCなどのパターンを使用します。このパターンでは、データのタイプ(モデル)に応じてビューを選択します。

MVVM
MVC
MVC for ASP.NET

于 2012-06-27T15:50:39.233 に答える
0

まず第一に、ジェネリックスを使用すると、より読みやすく短い、より優れたコードを記述できます。リポジトリにファクトリクラスを使用しない方が良いと思います。最終的には、次のようなコードでどのタイプを処理しているかを知る必要があります。

Child1 report = new Child1();
report.SomeBehaviorInChild1(); // this is not achievable with base class.

このファクトリを使用する場合は、次の操作を実行できます。ReportBase report = Factory.GetReport();

次に、クラスを使用しているユーザーが次のようなコードから新しいリストを作成することを望まないため、リストを公開することはお勧めできません。report._list = new List(); クラス内のオブジェクトにこのようなことが起こらないようにする必要があります。したがって、リストを非公開にし、レポートのデータソースを返すメソッドのみに依存することをお勧めします。プライベートリスト_list;

public List<T> GetDataSource()
{
     return _list;
}

第三に、ジェネリックレポートベースを実装する場合、ベースが実装していない特別なものがない限り、子クラスを作成する必要はありません。第4に、ここで行っているのはデータベースからすべてのレコードを取得し、それらをメモリでフィルタリングすることであるため、Filterメソッドの現在の実装は非常に悪いです。この実装は悪い習慣です。より良いアプローチは、遅延実行オブジェクトであるIQueryableを使用することです。つまり、要求するまで結果は入力されません。

public List<GetChild1> FilterExample()
{
    IQueryable<GetChild1> result = _context.GetChild1;
    result = from p in result
             where p.UploadDate < startDate;
             select p;
    //until this moment the query is still not send to the database.
    result = result.OrderBy(p => p.UploadDate);

    //when you call the ToList method the query will be executed on the database and the list of filtered and sorted items will be returned. Notice the sorting and filtering is done in the database which is faster than doing it in memory
    List<GetChild1> populatedResult = result.ToList();
    return populatedResult;
}

したがって、これは問題に対するより良いアプローチでした。クエリ可能でlinq全般について説明している「MoreEffectiveC#2008」という本を読むのは良いことだと思います。これをBaseReportClassに適用すると、次のようになります。

 //Base Class 
class ReportBase<T> where T: class
{
    private DbContext _context;
    public ReportBase(DbContext context)
    {
        _context = context;
    }


    //I think GetAll is a more suitable name for your method than load :D
    public IQueryable<T> GetAll()
    {
        return _context.Set<T>();
    }

    public IQueryable<T> Filter(Func<T,bool> filterFunction)
    {   
         var result = from p in GetAll()
                      where filterFunction(p)
                      select p;
         return result;
    }
}

次に、子クラスの追加の動作を定義します。

//Child 1
class Child1 : ReportBase<GetChild1>
{
   public ReportBase(DbContext context):base(context)
   {

   }

   public List<GetChild1> FilterOnStartDate(DateTime startDate)
   {
        //I don't know if you are familiar with lambda expressions but if you are not you can research it on the internet.
        //The parameter here is converted into a method that its parameter is "p" of type GetChild1
        // and the body is "p.UploadDate < startDate".
        // Note you can remove the type of the parameter because the compiler can predict it.
        return Filter((GetChild1 p) => p.UploadDate < startDate).ToList();
   }
} 

これは、クラスを使用するコードです。

Child1 report = new Child1(new GetChild1Entities());
report.FilterOnStartDate(DateTime.Now);

これがお役に立てば幸いです。

于 2012-06-28T08:11:51.030 に答える