MVC view model inheritance and create action

前端 未结 1 1585
小蘑菇
小蘑菇 2021-01-03 00:03

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

Given the following hypothetical model -



        
1条回答
  •  时光说笑
    2021-01-03 00:36

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

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

    0 讨论(0)
提交回复
热议问题