2

假设我有一个类似的界面:

interface IThing {
   int Id { get; set; }
   string Title { get; set; }
}

在 ASP.NET MVC 中,我有一个表单可以发布到这样的控制器操作:

 [AcceptVerbs(HttpVerbs.Post)]
 public ActionResult NewThing([Bind(Exclude = "Id")] SimpleThing thing) {

    // code to validate and persist the thing can go here            
 }

SimpleThing是一个具体的类,几乎没有实现IThing 。

但是,我希望我的所有方法都可以处理接口。我有一个使用 NIBerate 和它自己的IThing实现的数据程序集(我们称之为RealThing)。我无法将 SimpleThing 传递给它,因为它会抱怨“未知实体”。

有没有人对更清洁的方法有任何想法?我正在考虑使用工厂类的方法。但是我如何让 MVC 表单绑定器使用它呢?

谢谢!

4

4 回答 4

4

您可以使用自定义模型绑定器。但是关于 msdn 的文章完全没用。所以最好使用搜索并找到更好的东西。有大量可用的文章。

于 2009-07-03T21:40:12.477 回答
3

我想出了两种方法。

第一个是将代码添加到我的 NHibernate Repository 类中,以将 MVC 控制器 ( SimpleThing ) 使用的简单 POCO 类型转换为 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 想要的类型。显然这感觉有点笨拙,所以我研究了自定义模型活页夹。


在第二种方法中,我创建了一个自定义模型绑定器,如下所示:

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
}

我喜欢第二种方法,但我的大部分依赖注入东西都在 Controller 类中。我不想在 Global.asax.cs 中添加所有这些 ModelBinder 映射。

于 2009-07-04T13:57:24.480 回答
1

这里有一些很好的建议,我实际上想出了一个可行的解决方案。然而,我最终得到了一些东西。我刚刚为我发布的表单数据创建了特定的模型,并使用了默认的模型绑定器。

简单得多,它允许我捕获不属于我的域模型的数据(即像“评论”字段)。

于 2009-11-23T20:57:34.857 回答
0

这不是您的问题的直接答案。

我们使用略有不同的方法来处理您遇到的相同问题。我们的控制器接受逐字段匹配持久实体的 DTO。然后我们使用AutoMapper创建将进入数据库的持久实体。这消除了不必要的接口并锁定了面向公众的 API(意味着重命名持久性对象的字段不会破坏我们的客户端代码)。

于 2009-07-05T20:45:25.260 回答