Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC view model inheritance and create action

Tags:

c#

asp.net-mvc

I'm trying to work out the best architecture for handling model type hierarchies within an MVC application.

Given the following hypothetical model -

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; }
}

I could just create a controller for each type. Person would have just the index and detail action with the views making use of display templates, Teacher and Student would have just the Create/Edit actions. That would work but seems wasteful and wouldn't really scale because a new controller and views would be needed if another type was added to the hierarchy.

Is there a way to make a more generic Create/Edit action within the Person controller? I have searched for the answer for a while but can't seem to find exactly what I am looking for so any help or pointers would be appreciated :)

like image 968
mcricker Avatar asked Aug 07 '14 15:08

mcricker


People also ask

Should ViewModel inherit from model?

So my question is, why it is wrong to inherit from a Model class? Your ViewModel should be separate from your Model (i.e. Entity in this context). Remember a "ViewModel" is a model for the view. In other words it can display same, compact or transformed information of the original model.

What is ActionResult () in MVC?

An action result is what a controller action returns in response to a browser request. The ASP.NET MVC framework supports several types of action results including: ViewResult - Represents HTML and markup. EmptyResult - Represents no result.

How do you pass value from view to model?

The other way of passing the data from Controller to View can be by passing an object of the model class to the View. Erase the code of ViewData and pass the object of model class in return view. Import the binding object of model class at the top of Index View and access the properties by @Model.

What is ViewModel and model in MVC?

ViewModel = Model that is created to serve the view. ASP.NET MVC view can't have more than one model so if we need to display properties from more than one model in the view, it is not possible. ViewModel serves this purpose. View Model is a model class that can hold only those properties that are required for a view.

What is a ViewModel in MVC?

A ViewModel in ASP.NET MVC application is a model which contains more than one model data required for a particular view. As this model is specific for a particular view, we call this ViewModel in ASP.NET MVC. Let us have a look at the following diagram which shows the visual representation of a ViewModel in the MVC application.

How to create a model class in MVC?

Let’s create the Model class as follows, Once creating the new MVC Project Solution, right-click on the Model folder and add a new class Addà Class as shown below, Once adding the new class, give the proper name to the Model and click add. To create the model, this corresponds to the database table,

What is inheritance in ASP NET 4x?

ASP. NET 4.x In the previous tutorial you handled concurrency exceptions. This tutorial will show you how to implement inheritance in the data model. In object-oriented programming, you can use inheritance to facilitate code reuse.

Why do we need a ViewModel?

But many times, a single model is not sufficient to display data on the view. In real-time applications, we often feel a need of showing data from multiple models and some additional data which is not in the available models in the view section of our code. This is where the concept of ViewModel arose.


1 Answers

Sure, but it takes a little leg work.

First, in each of your edit/create views, you need to emit the type of model you are editing.

Second, you need add a new modelbinder for the person class. Here is a sample of why I would do for that:

public class PersonModelBinder :DefaultModelBinder
{

    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        PersonType personType = GetValue<PersonType>(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<T>(ModelBindingContext bindingContext, string key)
    {
        ValueProviderResult valueResult =bindingContext.ValueProvider.GetValue(key);

        bindingContext.ModelState.SetModelValue(key, valueResult);

        return (T)valueResult.ConvertTo(typeof(T));
    }  
}

Register it in your app start:

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

The PersonType is what I tend to use in each model and is an enum that says what each type is, I emit that in a HiddenFor so that it comes back in with the post data.

The SelectFor is a method that returns a type for the specified enum

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

You can now do something like this in your controller

public ActionResult Save(Person model)
{
    // you have a teacher or student in here, save approriately
}

Ef is able to deal with this quite effectively with TPT style inheritance

Just to complete the example:

public enum PersonType
{
    Teacher,
    Student    
}

public class Person
{ 
    public PersonType PersonType {get;set;}
}

public class Teacher : Person
{
    public Teacher()
    {
        PersonType = PersonType.Teacher;
    }
}
like image 163
Slicksim Avatar answered Oct 25 '22 00:10

Slicksim