MVC architecture - re-using the same viewmodel for reads and edits - asp.net-mvc

Say we have the following (overly simple) scenario:
We have a screen to view person details and a screen to edit person details.
The screen display person details has the following fields (as display only):
First Name
Last Name
Bio
The screen edit person details shows has following fields (in input controls):
ID (hidden)
First Name
Last Name
Bio
Say our display viewmodel looks like this:
public class DisplayPersonViewModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Bio { get; set; }
}
And our edit viewmodel looks like this:
public class EditPersonViewModel
{
[Required]
public int ID { get; set; }
[Required]
[StringLength(20)]
public string FirstName { get; set; }
[Required]
[StringLength(20)]
public string LastName { get; set; }
[Required]
public string Bio { get; set; }
}
Not much difference between the 2, eh? The edit model has one extra field (ID) and some of attributes on the properties. Now, if we were to combine the 2 like this:
public class DisplayPersonViewModel
{
[Required]
[StringLength(20)]
public string FirstName { get; set; }
[Required]
[StringLength(20)]
public string LastName { get; set; }
[Required]
public string Bio { get; set; }
}
public class EditPersonViewModel : DisplayPersonViewModel
{
[Required]
public int ID { get; set; }
}
This is certainly more DRY, since we don't have duplicate fields to maintain, but now we have extraneous info (attributes) on our display viewmodel. I'm leaning more towards the second approach, regardless, because some of our screens have over 25 fields! (...and that's out of my control, so please don't harp on it :) ...) However, I just want to hear opinions to get a better sense of what may be "best practice".

Yes, the second approach seems fine to me. No worries other than this itchy feeling in your stomach telling you why on earth are you decorating a display view model with validation attributes. But if you can live with it it's really something that is preferred compared to duplicating the view models.
Unfortunately personally I cannot live with this feeling in my stomach and that's why I use FluentValidation.NET to define my validation rules instead of data annotations. It allows me to have those rules separately from my view models and then I don't worry about polluting the so called display view model with validation rules. So I would define in the same way as you 2 view models and EditPersonViewModel would derive from DisplayPersonViewModel and then define my EditPersonViewModelValidator for the EditPersonViewModel in a separate class.
Oh and a side note: decorating a non-nullable type with the [Required] attribute is not necessary. All non-nullable types are required by their very basic nature. So instead of:
[Required]
public int ID { get; set; }
you should only have:
public int ID { get; set; }

Another option is to use the MetadataType Attribute.
public class PersonModel
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Bio { get; set; }
}
[MetadataType(typeof(IDisplayPersonViewModel))]
public class DisplayPersonViewModel : PersonModel
[MetadataType(typeof(IEditPersonViewModel))]
public class EditPersonViewModel : PersonModel
public interface IDisplayPersonViewModel
{
[ScaffoldColumn(false)]
public int ID { get; set; }
}
public interface IEditPersonViewModel
{
[Required]
[StringLength(20)]
public string FirstName { get; set; }
[Required]
[StringLength(20)]
public string LastName { get; set; }
[Required]
public string Bio { get; set; }
[Required]
public int ID { get; set; }
}
Your raw Person model is attribute free. Your Display and Edit models only have the attributes you actually need for the View.

Related

HowTo fetch data to viewmodel the quickest way

I have a simple problem with my site.
Inside my site, I'm using two different models, with some identical named fields.
Because of collision, I have to give them unique names and for not loosing the modelbinding, I decided to use viewModels.
So I have a Model like this:
namespace MySite.Models
{
public class Function : BaseEntity
{
//Beziehung zur Funktionsgruppe
[Required]
[Display(Name = "Übergeordnete Funktion")]
public int FunctionGroupId { get; set; }
public virtual FunctionGroup FunctionGroup { get; set; }
[Required]
[StringLength(200)]
[Display(Name = "Bezeichnung")]
public string Name { get; set; }
}
}
And I have a new ViewModel like this:
namespace MySite.ViewModels
{
public class FunctionViewModel
{
//Properties of BaseEntity
public int F_Id { get; set; }
[Display(Name = "Erstellt")]
public string F_Created { get; set; }
[Display(Name = "Bearbeitet")]
public string F_LastChange { get; set; }
[Display(Name = "Bearbeiter")]
public string F_ByUser { get; set; }
//Beziehung zur Funktionsgruppe
[Required]
[Display(Name = "Übergeordnete Funktion")]
public int F_FunctionGroupId { get; set; }
public virtual FunctionGroup F_FunctionGroup { get; set; }
[Required]
[StringLength(200)]
[Display(Name = "Bezeichnung")]
public string F_Name { get; set; }
}
}
Now my Question is, is there a way to automatically fetch the data of the corresponding model, while loading the ViewModel?
Something like a kind of function directly inside the { get; set; }?
Actually I load field by field form the model into the ViewModel.
Hope that I could have described Right, what I'd like to do.
Carsten
You can use Automapper for mapping or getting your data from Model to ViewModel or vice-versa. It will be hard for you to map/configure if your name of your property is different so have the same name in view model as well. (If possible)

ASP.NET MVC EF 6: define a lookup table/model

i am trying to define a database model in code-first to see and display which user is assigned as a specialist for the record data.
I have a very simple model for the user:
public class User
{
public int ID { get; set; }
public string userName { get; set; }
public string firstName { get; set; }
public string lastName { get; set; }
....
}
Next I have defined two (simple) models which define the data that can be edited by the user and the specialist should be assigned to using a dropdownlist:
public class Order
{
public int ID { get; set; }
public string orderNumber { get; set; }
public int specialistID { get; set; }
public virtual User specialist{ get; set; }
}
public class Part
{
public int ID { get; set; }
public string partNumber { get; set; }
public string description { get; set; }
public int specialistID { get; set; }
public virtual User specialist{ get; set; }
}
What kind of relation between the models can be used without having a navigation property for each table in the User model?
Do I need to use additional tables to define the relationship: User.Id-Order.specialistID and the relationship: User.Id-Part.specialistID ?
Is there a smarter way out-of-the-box by Entity Framework?
Many thanks for your answers.
Pascal
By default when you add forign-key constraint to the many-to-one table the Entity Framework add virtual property to the entity class and virtual ICollection to the User.

Display different parts of model in EditorTemplate in MVC

When creating a form for a Store I have one ContactPerson and one EconomyPerson. For each of them I need the name to be required but the email should not even be visible in the form for the EconomyPerson.
I would like to use the EditorTemplate for my class Person. But can I hide input fields and change the validation requirements from the Store class?
public class Person
{
[Required]
public String FirstName { get; set; }
[Required]
public String LastName { get; set; }
[Required]
public String Email { get; set; }
[Required]
public String PhoneNumber { get; set; }
public String MobileNumber { get; set; }
}
public class Store
{
[Required]
public Person ContactPerson { get; set; }
[Required]
public Person EconomyPerson{ get; set; }
}

Retrieving [DisplayName] DataAnnotation in T4 template

I have downloaded the MVCScaffolding nuget package within VS2010. I am trying to retrieve a [DisplayName data annotation from my model in order to use it within the index.cs.t4 template.
This page OneToMany Relationships has shown me how to modify the index template in order to provide a link which will take me to the controller index for my child objects. Which in this case from emails to emailrecipients. The problem is i have called my controllers emailcontroller and emailrecipientscontroller rather than their rather less descriptive tables names which i would prefer to hide anyway. i have equally decorated the metadataobject which the t4 template uses(tbl_My_unwieldytablename_emailMetadata) with this displayname (emailrecipients) dataannotation and i was hoping i could modify the template in order to replace the name for the relation to use the displayname which is my controller name i.e.
[MetadataType(typeof(tbl_My_unwieldytablename_emailMetadata))]
public partial class tbl_My_unwieldytablename_email
{
internal sealed class tbl_My_unwieldytablename_emailMetadata
{
[ScaffoldColumn(false)]
[Required(ErrorMessage="id is required")]
public Int32 id { get; set; }
[DataType(DataType.Date)]
public DateTime send_date { get; set; }
[StringLength(255)]
public String title { get; set; }
[DataType(DataType.MultilineText)]
public String message { get; set; }
[StringLength(50)]
public String author { get; set; }
[StringLength(80)]
[DataType(DataType.EmailAddress)]
public String author_email { get; set; }
[DataType(DataType.MultilineText)]
public String attachment { get; set; }
[DataType(DataType.Date)]
public DateTime created_date { get; set; }
public Int32 batches { get; set; }
[DataType(DataType.Date)]
public DateTime complete_date { get; set; }
[DisplayName("emailrecipients")]
public EntityCollection<tbl_My_unwieldytablename_email_recipients> tbl_My_unwieldytablename_email_recipients { get; set; }
}
Cheers
Tim
[Table("tbl_My_unwieldytablename_email")]
Public Class Email
[Table("tbl_My_unwieldytablename_email_recipients")]
Public Class EmailRecipients
Should map your classes to the database tables

.NET MVC Render Views with custom data annotations

Playing around a little bit with a .NET MVC web application, and have questions about ViewModels and the data annotations.
Lets say I have a ViewModel:
public class MyViewModel
{
[DisplayName("First Name")]
public string FirstInfoName { get; set; }
[DisplayName("First Information")]
public string FirstInfo { get; set; }
[DisplayName("Second Name")]
public string SecondInfoName { get; set; }
[DisplayName("Second Information")]
public string SecondInfo { get; set; }
[DisplayName("Third Name")]
public string ThirdInfoName { get; set; }
[DisplayName("Third Information")]
public string ThirdInfo { get; set; }
}
When I want to create an Edit view my ViewModel I use:
#Html.EditorForModel()
This works great, MVC will render textboxes for me. But let's say that I want to render tabs in my view, So the properties of the ViewModel will be grouped depending on data annotations.
Example:
public class MyViewModel
{
[Tab(1)]
[DisplayName("First Name")]
public string FirstInfoName { get; set; }
[Tab(1)]
[DisplayName("First Information")]
public string FirstInfo { get; set; }
[Tab(2)]
[DisplayName("Second Name")]
public string SecondInfoName { get; set; }
[Tab(2)]
[DisplayName("Second Information")]
public string SecondInfo { get; set; }
[Tab(3)]
[DisplayName("Third Name")]
public string ThirdInfoName { get; set; }
[Tab(3)]
[DisplayName("Third Information")]
public string ThirdInfo { get; set; }
}
Is it possible to do something like this? Maybe using templates?
While i'm not going to say you can't do this, it is certainly not going to be an easy solution. The reason is attributes are evaluated on a per property basis. Tabs are typically displayed withing a group, and there's not a good way to alter your html to include groups based on multiple attributes of the same type.

Resources