私はこれに対して2つのアプローチを思いついた。
1つ目は、NHibernateリポジトリクラスにコードを追加して、MVCコントローラーで使用される単純なPOCOタイプ(SimpleThing)をNHibernateが必要とするエンティティのタイプ( RealThing )に変換することでした。
/// <summary>
/// A NHibernate generic repository. Provides base of common
/// methods to retrieve and update data.
/// </summary>
/// <typeparam name="T">The base type to expose
/// repository methods for.</typeparam>
/// <typeparam name="K">The concrete type used by NHibernate</typeparam>
public class NHRepositoryBase<T, K>
: IRepository<T>
where T : class
where K : T, new()
{
// repository methods ...
/// <summary>
/// Return T item as a type of K, converting it if necessary
/// </summary>
protected static K GetKnownEntity(T item) {
if (typeof(T) != typeof(K)) {
K knownEntity = new K();
foreach (var prop in typeof(T).GetProperties()) {
object value = prop.GetValue(item, null);
prop.SetValue(knownEntity, value, null);
}
return knownEntity;
} else {
return (K)item;
}
}
したがって、リポジトリ内の任意のメソッドがGetKnownEntity(T item)を呼び出すことができ、渡されたアイテムのプロパティをNHibernateが必要とするタイプにコピーします。明らかにこれは少し不格好に感じたので、私はカスタムモデルのバインダーを調べました。
2番目のアプローチでは、次のようなカスタムモデルバインダーを作成しました。
public class FactoryModelBinder<T>
: DefaultModelBinder
where T : new()
{
protected override object CreateModel(ControllerContext controllerContext,
ModelBindingContext bindingContext,
Type modelType) {
return new T();
}
}
次に、それをGlobal.asax.csに次のように登録しました。
ModelBinders.Binders.Add(typeof(IThing),
new FactoryModelBinder<RealThing>());
そして、次のようなコントローラーアクションで正常に動作します。
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult NewThing([Bind(Exclude = "Id")] IThing thing) {
// code to process the thing goes here
}
私は2番目のアプローチが好きですが、依存性注入に関するもののほとんどはControllerクラスにあります。Global.asax.csにこれらすべてのModelBinderマッピングを追加する必要はありません。