0

I have little experience with Database First Models and how to approach these with MVC View Models.

It is clear I cannot change the original model but I would like to add some annotations to the model for validation purposes.

Therefore what I tried to do was create a ViewModel which inherits from the entity

My DB First generated model - do not amend

public partial class xmldata
{
    public string ISBN { get; set; }
    public string title { get; set; }
    public string blurb { get; set; }
    ...
}

I then created a view model as follows which inherits from xmldata

public class XmlDataViewModel : xmldata
{
    [AllowHtml]
    [Display(Name = "Blurb")]
    public string BlurbVm {
        get { return blurb; }
        set { blurb = value; }
    }
    ...
}

The field shown above I needed to AllowHtml and my best solution so far but however in the controller actions I have still had to manually map the BlurbVm field back to blurb even though i would of thought the setter above would of handled that (im using Automapper for the rest of the fields) so I am confused as to why this didn't work.

Also at the moment I am doing Validations in the controller and may want to refactor this later to move them into the View Model so I can use the [Required] annotation and also [Display (Name="Title")] fields which are currently handled in the view.

Probably my overall question here is am I using the best strategy for dealing with Model Annotations and view models when using a Database First Model.

Frazer
  • 560
  • 2
  • 11
  • 21
  • 6
    A view model does not inherit a data model. It is a completely separate model and has no knowledge at all of a data model. [What is ViewModel in MVC?](http://stackoverflow.com/questions/11064316/what-is-viewmodel-in-mvc) –  Oct 12 '16 at 10:05
  • 1
    Yes, one of the biggest mistakes you can make is reusing your data models as view models. You are in for a world of pain! – Charleh Oct 13 '16 at 08:30

2 Answers2

5

I thought I might add some detailed explanation on why data model is different from view model

Difference between model and view model

You are mixing two different things, as @Stephen Muecke mentioned in comments. View model serves one purpose - take data from controller and transfer it to to view. In complicated cases data you want to show the user is completely different from what your database looks like. To represent your data structure in your code you use data model. It has exactly the same properties as you have in your database.

However view model shouldn't know about how your data is structured. You just simply assign its properties and pass those data to the view.

Consider following example. You have Customers and Orders tables in your database.

Customers:

ID | Firstname | Lastname

Orders:

ID | Amount | CustomerID

In order to map those data in your code you would have to create two classes

public class Customer
{
    public int ID { get; set; }
    public string Firstname { get; set; }
    public string Lastname { get; set; }
}

public class Order
{
    public int ID { get; set; }
    public decimal Amount { get; set; }
    public int CustomerID { get; set; }
}

But in your application you have some view, where you want to display customers first names and total amount they've spent in your shop. You could create view model, which will serve exactly this purpose.

public CustomersViewModel
{
    public string Firstname { get; set; }
    public decimal TotalAmount { get; set; }
}

See how different this view model is, compared to your data model? It doesn't know about ID value nor about Lastname.

This model is used only to display your data properly, so here you can use all DataAnnotations you want.

public CustomersViewModel
{
    public string Firstname { get; set; }

    [DisplayFormat(DataFormatString="{0:#.####}")]
    public decimal TotalAmount { get; set; }
}

Why on MSDN they're annotating data models?

Because like @CodeCaster mentioned - it's bad practice, but it's not forbidden. If your application is really simple, you can skip view models altogether! Is it a bad idea? Yes - even in simple cases you should use dedicated view models, because it costs you nothing, but decouples your views from your data structure. I guess they didn't want to complicate those examples, so when reading this tutorials you should focus only on how to use DataAnnotations.

How to bind custom view model in your controller?

Usage of view models is not limited to returning them to views in order to simply display some data. You can use them, if you want to pass data for the user to modify it. It is absolutely acceptable to have view model, which have exactly the same properties as your data model. Considering previous example, we could have CustomerViewModel which we can use in EditCustomer.cshtml view.

In this view we could have our edit form looking like this

@model CustomerViewModel

// HTML markup
@Html.LabelFor(m => m.Firstname)
@Html.TextboxFor(m => m.Firstname)
// another properties similar

If our Edit method in CustomerController would look like this

public Edit(CustomerViewModel customer)

there is not much we have to do more. ASP.NET will automatically bind posted form with customer of type CustomerViewModel. Now we only have to pass data stored in customer into appropriate data model and save it in database.

Paweł Hemperek
  • 1,130
  • 10
  • 21
  • Thanks for this, I can understand why you should separate the Data Model from the View Model and therefore the annotations to achieve decoupling, but what I would like a little more information about how you to the binding later on in the controllers. At the moment it would appear that my controllers are slick, but it would appear with your example that I would need to do much more manual mapping in the controllers to make this work particularly for Create and Update. – Frazer Oct 13 '16 at 08:12
  • I have just removed my inheritance of xmldata and copied the properties and its worked, thank you. I still however have issues with my BlurbVm property relating to allowing Html which I have not been able to resolve, removing this and adding [AllowHtml] to blurb in the ViewModel did not seem to work. – Frazer Oct 17 '16 at 11:22
  • Exactly what is your problem? HTML is encoded or there is not value at all? Glad I could helped! – Paweł Hemperek Oct 17 '16 at 11:25
  • OK, so i have removed BlurbVm and in my view model added [AllowHtml] to the public string blurb { get; set; } property in the VM. This contains legitimate HTML, the Controller falls over "A potentially dangerous Request.Form value." at UpdateModel(dbXmldata) dbXmldata being the EntityContext database record. – Frazer Oct 17 '16 at 11:53
0

You can add data annotation to your main domain model. While creating manual data annotation ensure that namespace are equal with generated class's namespace.

[MetadataType(typeof(XmlDataDataAnnotation))]
public partial class xmldata{ }

public class XmlDataDataAnnotation
{
  [AllowHtml]
  [Display(Name = "Blurb")]
  public string blurb { get; set; }
}

Then you can create complex property in your view model.

public class XmlDataViewModel
{
  public xmldata XmlData {get;set;}
}

Also please see below link for clarification:

Add data annotations to a class generated by entity framework

Data Annotations with Entity Framework 5.0 (database first)

Community
  • 1
  • 1
Power Star
  • 1,724
  • 2
  • 13
  • 25
  • 2
    Annotating an Entity Framework model with MVC attributes is a bad practice. – CodeCaster Oct 12 '16 at 10:28
  • Microsoft suggested this. Creating new property and assigning is also bad. – Power Star Oct 12 '16 at 10:29
  • https://www.asp.net/mvc/overview/getting-started/database-first-development/enhancing-data-validation – Power Star Oct 12 '16 at 10:34
  • 1
    Look, you're missing the point. First of all, the OP should not inherit viewmodels from entity models. Use separate viewmodels altogether. Second, you shouldn't be using MVC-specific attributes on entity classes. Third, you're not only inheriting from `xmldata`, but _also_ including a property of that type, so your `XmlDataViewModel` both is-a and has-a `xmldata`, which makes no sense. So this answer demonstrates bad advice altogether (and MVC tutorials that use entity models as viewmodels are spreading bad advice equally). – CodeCaster Oct 12 '16 at 10:45
  • I m sorry.. I forgot to remove inherited class from view model, now i removed.. But I don't accept second point. B coz I m not adding attribute to auto genera ted class file. Please give me solution, i will thankful to u. – Power Star Oct 12 '16 at 11:06