MVC视图模型继承和创建操作

30 浏览
0 Comments

MVC视图模型继承和创建操作

我正在尝试找出在MVC应用程序中处理模型类型层次结构的最佳架构。

给定以下假设模型 -

public abstract class Person
{
    public string Name { get; set; }
}
public class Teacher : Person
{
    public string Department { get; set; }
}
public class Student : Person
{
    public int Year { get; set; }
}

我可以为每个类型创建一个控制器。Person只有索引和详细操作,视图使用显示模板,Teacher和Student只有创建/编辑操作。这样做是可行的,但似乎有些浪费,并且不会真正扩展,因为如果添加了另一个类型到层次结构中,就需要一个新的控制器和视图。

有没有办法在Person控制器中创建一个更通用的创建/编辑操作?我已经搜索了一段时间,但似乎找不到我要找的答案,所以任何帮助或指引将不胜感激 🙂

0
0 Comments

MVC视图模型继承和创建操作的问题出现的原因是需要根据不同的模型类型来选择对应的视图或部分视图进行填写。解决方法是使用模型绑定器来根据提交的数据类型选择相应的模型,并使用EditorFor方法来自动查找对应名称的视图进行填写。

首先,在每个编辑/创建视图中,需要发出要编辑的模型类型。

其次,需要为Person类添加一个新的模型绑定器。以下是一个示例:

public class PersonModelBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        PersonType personType = GetValue(bindingContext, "PersonType");
        Type model = Person.SelectFor(personType);
        Person instance = (Person)base.CreateModel(controllerContext, bindingContext, model);
        bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => instance, model);
        return instance;
    }
    private T GetValue(ModelBindingContext bindingContext, string key)
    {
        ValueProviderResult valueResult = bindingContext.ValueProvider.GetValue(key);
        bindingContext.ModelState.SetModelValue(key, valueResult);
        return (T)valueResult.ConvertTo(typeof(T));
    }
}

在应用程序启动时注册它:

ModelBinders.Binders.Add(typeof(Person), new PersonModelBinder());

PersonType是我在每个模型中使用的枚举类型,用于表示每种类型,我会在HiddenFor中发出它,以便它随着提交的数据一起返回。

SelectFor是一个根据指定的枚举返回类型的方法。

public static Type SelectFor(PersonType type)
{
    switch (type)
    {
        case PersonType.Student:
            return typeof(Student);
        case PersonType.Teacher:
            return typeof(Teacher);
        default:
            throw new Exception();
    }
}

现在你可以在控制器中这样做:

public ActionResult Save(Person model)
{
    // 在这里你有一个教师或学生,适当地保存
}

EF能够以TPT风格的继承有效地处理这个问题。

完整的示例代码如下:

public enum PersonType
{
    Teacher,
    Student    
}
public class Person
{ 
    public PersonType PersonType {get;set;}
}
public class Teacher : Person
{
    public Teacher()
    {
        PersonType = PersonType.Teacher;
    }
}

PersonType是一个枚举类型,你可以直接使用指定的类型,但为了安全起见,我更喜欢使用枚举。

如果你在创建操作中使用EditorFor,并且在控制器的View文件夹或Shared文件夹中命名视图与类名相同,MVC将根据约定自动查找视图。

可以这样使用.EditorForModel(derivedClassName)。这样,如果我提供了派生类的名称,并且有一个同名的编辑模板,我假设调用.Editor(derivedClassName)将插入模板。

我指的是.EditorForModel(derivedClassName)。

你可以使用.EditorForModel()。MVC会在EditorTemplates文件夹中根据模型的类名查找视图。所以你不需要提供它,它会根据名称查找。这意味着在创建或编辑中,你可以使用一个名为Create或Edit的存根视图,只需调用editorformodel,MVC将为你插入正确的视图。

你需要添加using System.Web.Mvc;

这个解决方案对我很有帮助。但是我没有看到GetValue方法中设置模型值的必要性。即使没有那行代码,我仍然可以在我的post方法中获取模型值。那行代码的作用是什么?

0