2

オブジェクトがあるとしましょう

class MyItem
{
     public string Name {get; set;}
     public string Description {get; set;}
}

ViewModel を作成したい

class MyItemViewModel
{
     public string Name {get; set;}
     public string Description {get; set;}
     public string Username {get; set;}
}

コントローラーで MyItem 型のオブジェクトを取得し、ViewModel を自動的に設定したいと思います。MyItem に含まれる値を使用します (つまり、Name というプロパティがある場合は、自動的に入力されます)。

私が避けようとしているのは、Model.Name = Item.Name行のリストです。MyItemViewModel にもさまざまな属性と表示値があるため、ビュー モデル内に MyItem を単純に埋め込むことはできません。

オブジェクト間で同じ名前とタイプの属性を複製するプログラムによるクリーンな方法はありますか?

4

3 に答える 3

5

このタスクにはAutoMapperを使用できます。ドメインモデルとビューモデルの間でマッピングするために、すべてのプロジェクトでこれを使用しています。

Application_Start:でマッピングを定義するだけです。

Mapper.CreateMap<MyItem, MyItemViewModel>();

次に、マッピングを実行します。

public ActionResult Index()
{
    MyItem item = ... fetch your domain model from a repository
    MyItemViewModel vm = Mapper.Map<MyItem, MyItemViewModel>(item);
    return View(vm);
}

また、OnActionExecutedメソッドをオーバーライドし、ビューに渡されたモデルを対応するビューモデルに置き換えるカスタムアクションフィルターを作成できます。

[AutoMap(typeof(MyItem), typeof(MyItemViewModel))]
public ActionResult Index()
{
    MyItem item = ... fetch your domain model from a repository
    return View(item);
}

これにより、コントローラーのアクションが非常に簡単になります。

AutoMapperには、何かを更新したいときにPOSTアクションで使用できるもう1つの非常に便利なメソッドがあります。

[HttpPost]
public ActionResult Edit(MyItemViewModel vm)
{
    // Get the domain model that we want to update
    MyItem item = Repository.GetItem(vm.Id);

    // Merge the properties of the domain model from the view model =>
    // update only those that were present in the view model
    Mapper.Map<MyItemViewModel, MyItem>(vm, item);

    // At this stage the item instance contains update properties
    // for those that were present in the view model and all other
    // stay untouched. Now we could persist the changes
    Repository.Update(item);

    return RedirectToAction("Success");
}

たとえば、Username、Password、IsAdminなどのプロパティを含むUserドメインモデルがあり、ユーザーがユーザー名とパスワードを変更できるが、IsAdminプロパティは絶対に変更できないフォームがあるとします。したがって、ビュー内のhtmlフォームにバインドされたUsernameプロパティとPasswordプロパティを含むビューモデルがあり、この手法を使用すると、IsAdminプロパティは変更されずに、これら2つのプロパティのみが更新されます。

AutoMapperはコレクションでも機能します。単純型間のマッピングを定義したら、次のようにします。

Mapper.CreateMap<MyItem, MyItemViewModel>();

コレクション間でマッピングする場合、特別なことをする必要はありません。

IEnumerable<MyItem> items = ...
IEnumerable<MyItemViewModel> vms = Mapper.Map<IEnumerable<MyItem>, IEnumerable<MyItemViewModel>>(items);

だからもう待つ必要はありません。NuGetコンソールで次のコマンドを入力して、ショーを楽しんでください。

Install-Package AutoMapper
于 2012-08-15T13:57:13.690 に答える
2

これを行うにはリフレクションが必要な場合があります

これがその例です

フル :リフレクションによる単純なプロパティ マッパー: オブジェクトの各プロパティを手動でコピーするのはやめましょう!

 /// <summary>
    /// Copies all the properties of the "from" object to this object if they exist.
    /// </summary>
    /// <param name="to">The object in which the properties are copied</param>
    /// <param name="from">The object which is used as a source</param>
    /// <param name="excludedProperties">Exclude these properties from the copy</param>
    public static void copyPropertiesFrom
    (this object to, object from, string[] excludedProperties)
    {
      Type targetType = to.GetType();
      Type sourceType = from.GetType();

      PropertyInfo[] sourceProps = sourceType.GetProperties();
      foreach (var propInfo in sourceProps)
      {
        //filter the properties
        if (excludedProperties != null
          && excludedProperties.Contains(propInfo.Name))
          continue;

        //Get the matching property from the target
        PropertyInfo toProp =
          (targetType == sourceType) ? propInfo : targetType.GetProperty(propInfo.Name);

        //If it exists and it's writeable
        if (toProp != null && toProp.CanWrite)
        {
          //Copy the value from the source to the target
          Object value = propInfo.GetValue(from, null);
          toProp.SetValue(to,value , null);
        }
      }
    }
于 2012-08-15T13:59:34.147 に答える
1

ゼロからやりたい場合は、いくつかのリフレクション コードが役立ちます。パフォーマンスは高くありませんが、セットアップと保守は確かに簡単です。このSO answerで提供されている方法を確認してください。

「Type.GetProperties」を使用して、ターゲット オブジェクトのプロパティのリストを取得できます。

MSDNの記事はこちら

パブリック プロパティを取得する例:

PropertyInfo[] myPropertyInfo = myType.GetProperties(BindingFlags.Public|BindingFlags.Instance);
于 2012-08-15T13:59:48.523 に答える