7

リポジトリ クラスを作成して、データ ロジックをコントローラーから分離したいと考えています。ViewModel を使用して、さまざまなテーブルのデータで埋められるデータを表しています。

ここに私が持っているいくつかの質問があります:

  1. のようなメソッドの場合、またはGetAll()を返しますIQueryable<MyViewModel>IQueryable<Entity>? GetAll()ビューモデルを返す場合、何千ものレコードをプル する にどう対処すればよいですか?
  2. マッピングを行うためのパラメーターとして Entity を受け取るカスタム ViewModel クラスのコンストラクターを作成する必要がありますか? (私はまだオートマッパーに慣れていないので、設計の観点からこれを行う方法を理解する必要があります)

繰り返しますが、私の主な関心事は、GetAll()多くのレコードを取得するような方法です。各エンティティを ViewModel に変換するために foreach ループを実行すると、多くのオーバーヘッドが発生するように思えます。私の考えは、カスタム ViewModel クラス内にIQueryable<Entity>コレクションからアクセスするための参照を配置し、ListViewModel にコレクション プロパティを参照するインデクサーまたはそのようなものを持たせることでした。

4

3 に答える 3

5

1) GetAll() のようなメソッドの場合、IQueryable または IQueryable を返しますか? ビューモデルを返す場合、何千ものレコードを取得する GetAll() にどのように対処すればよいですか?

IQueryable<Entity>. リポジトリはビュー モデルを扱いません。リポジトリは、ビュー モデルが存在する ASP.NET MVC アプリケーションを参照しない別のクラス ライブラリで定義されているものと考えてください。このライブラリを参照するのは ASP.NET MVC アプリケーションです。

2) Entity をパラメーターとしてマッピングを行うカスタム ViewModel クラスのコンストラクターを作成する必要がありますか? (私はまだオートマッパーに慣れていないので、設計の観点からこれを行う方法を理解する必要があります)

いいえ。ビュー モデルにコンストラクターを作成しないでください。特に、コントローラー アクションでそれらのビュー モデルをアクション パラメーターとして使用する場合は (POST アクションを考えてください)、コンストラクターを作成しないでください。これは、既定のモデル バインダーがビュー モデルをインスタンス化する方法を認識できなくなり、カスタム モデル バインダーを作成する必要があるためです。

したがって、AutoMapper または手動でマッピングします。

あなたが始めることができる手動マッピングの例:

public ActionResult SomeAction()
{
    IEnumerable<Entity> entities = Repository.GetAll();
    IEnumerable<MyViewModel> model = entities.Select(x => new MyViewModel
    {
        Prop1 = x.Prop1,
        Prop2 = x.Prop2,
        ...
    }); 
    return View(model);
}

そして、このコードを書くのにうんざりしたら、AutoMapper に移動します。

public ActionResult SomeAction()
{
    IEnumerable<Entity> entities = Repository.GetAll();
    IEnumerable<MyViewModel> model = Mapper.Map<IEnumerable<Entity>, IEnumerable<MyViewModel>>(entities); 
    return View(model);
}

または、OnActionExecuted イベントを使用してビューに渡されたドメイン モデルをプルするカスタム アクション フィルターを作成し、AutoMapper を使用してそれをビュー モデルにマップし、モデルをビューのビュー モデルに置き換える場合、さらに単純化できます。反復コード:

[AutoMap(typeof(IEnumerable<Entity>), typeof(IEnumerable<MyViewModel>))]
public ActionResult SomeAction()
{
    IEnumerable<Entity> entities = Repository.GetAll();
    return View(entities);
}

繰り返しますが、私の主な関心事は、多くのレコードをプルする GetAll() のようなメソッドです。各エンティティを ViewModel に変換するために foreach ループを実行すると、多くのオーバーヘッドが発生するように思えます。

それについて心配しないでください。レコードをプルすると、ループしてビュー モデルにマッピングするよりも大幅に遅くなります。

于 2012-08-14T05:42:23.350 に答える
1

ビューモデルとその目的を誤解している可能性があると思います。データベース内のすべてのエンティティに対してビュー モデルを作成する必要はありません。レンダリングするビューごとにビュー モデルを作成するだけです。したがって、「ビュー モデル」という用語は、ビューを厳密に型指定できるモデルの形式でデータを編成します。

たとえば、GetAll() によって返されるエンティティごとに個別のビュー モデルを作成する必要はありません。すべてのレコードのグリッドビューを表示する単純なシナリオでは、おそらく 1 つのプロパティを持つ単一のビューモデルが必要になるでしょう:

    public class MyViewModel
    {     
       public List<MyRecord> AllRecords {get;set;}
    }

このビューモデルをコントローラーに入力します

public ActionResult SomeAction()
{
   var viewmodel = new MyViewModel{AllRecords = GetAll()};
   return View(viewModel);
}

非常に簡潔な議論については、Rachael Appel によるこのブログ投稿をご覧ください。

于 2012-08-14T00:40:36.917 に答える
1

これを行うにはさまざまな方法がありますが、簡単に説明するIEnumerable<T>と、GetAll() メソッドに対して を返します。ただし、おそらく何らかの方法でページングを実装したいと思うでしょう。ほとんどのシナリオで基本的なデータ アクセスを行い、Enumerable を返す汎用リポジトリをセットアップすることをお勧めします。より複雑なクエリ用に予約する必要がある単一のメソッドを予約して、IQueryable<T>. 基本的な簡素化された実装は、次のようになります。

public class Repository<T> : IRepository<T> where T : class
{
    internal ObjectContext _objectContext;
    internal ObjectSet<T> _objectSet;

    public Repository(ObjectContext objectContext)
    {
        _objectContext = objectContext;
        _objectSet = objectContext.CreateObjectSet<T>();
    }

    public IQueryable<T> GetQuery()
    {
        return _objectSet;
    }

    public IEnumerable<T> GetAll()
    {
        return GetQuery().ToList();
    } 

    public IEnumerable<T> Find(Func<T, bool> where)
    {
        return _objectSet.Where<T>(where);
    }

    public T Single(Func<T, bool> where)
    {
        return _objectSet.SingleOrDefault<T>(where);
    }

    public List<T> Page<TKey>(Expression<Func<T, bool>> where, int page, int pagesize, Expression<Func<T, TKey>> orderBySelector, bool ascending)
    {
        return ascending
            ? GetQuery().Where(where).OrderBy(orderBySelector).Skip((page - 1) * pagesize).Take(pagesize).ToList()
            : GetQuery().Where(where).OrderByDescending(orderBySelector).Skip((page - 1) * pagesize).Take(pagesize).ToList();
    }


    public void Delete(T entity)
    {
        _objectSet.DeleteObject(entity);
    }

    public void Add(T entity)
    {
        _objectSet.AddObject(entity);
    }

}

インターフェイスは次のようになります

public interface IRepository<T> where T : class
{
    IQueryable<T> GetQuery();

    IEnumerable<T> GetAll();

    IEnumerable<T> Find(Func<T, bool> where);     

    T Single(Func<T, bool> where);

    List<T> Page<TKey>(Expression<Func<T, bool>> where, int page, int pagesize, Expression<Func<T, TKey>> orderBySelector, bool ascending);

    void Delete(T entity);

    void Add(T entity);

}

上記は、単純な汎用リポジトリの始まりとして機能できます。エンティティを取得したら、AutoMapper は必要ありません。多くの ViewModel がエンティティと同じプロパティを持つため、作業が楽になります。新しい ViewModel または ViewModel のリストを定義し、独自にプロパティをマップするだけです。

List<ViewModel> vm = new List<ViewModel>();

foreach (var e in entities)
{
    ViewModel v = new ViewModel();
    v.something = e.something;
    // perform the rest
    vm.Add(v);
}

※入力がかなり長かったので、誤字脱字はご容赦ください(笑)

于 2012-08-13T23:33:59.463 に答える