Bonga
Bonga

Reputation: 97

How does Entity Framework identify my view models and bind to my domain model's properties?

From my understanding, a view model represents only the data that I would like to display in a particular view and can consist of properties from multiple domain models. I also understand that view models act as a data-binder between my domain models and views.

With that said, I have the following model:

public class Image
{
    public int ImageID { get; set; }
    public string ImageCaption { get; set; }
    public int NumOfLikes { get; set; }
    public string ImageFilePath { get; set; }
}

And a ProfileViewModels class with the the following view models:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;

namespace Splend.Models
{
    public class ImageUploadViewModel
    {
    }

    public class EditUserProfileViewModel
    {
    }

    public class ViewUserProfileViewModel
    {
    }

    public class ViewImagesViewModel
    {
    }
}

Firstly, I assumed that this is the correct way of creating view models based on AccountViewModels generated by ASP.NET Identity. Secondly, I have not scaffolded any items from these two models. So I have no views or controllers yet.


Questions

  1. How would my view models bind data between my domain model and views?
  2. How would I map my view models to my domain models?
  3. How does Entity Framework know that my view model properties are referenced from my domain model and that I am not creating new model properties, i.e. is there a particular view model and property naming convention that I have to use to tell Entity Framework that ImageUploadViewModel is a view model?

Upvotes: 2

Views: 1660

Answers (1)

Luke
Luke

Reputation: 23690

I wouldn't recommend a one-size-fits-all approach to creating and managing view models cause it gets complicated quickly, especially if you come to assign validation to them.

It seems like you're trying to anticipate the view models that you need before you create your views?

Generally I would recommend having a 1:1 relationship between your view models and your views and ensure that your view models contain the least amount of fields to hold only the information that is required to display said view.

I have assumed that you have a users that have multiple Images and the following view models:

public class ProfileViewModel
{
    public string UserName { get; set; }
    public string Password { get; set; }
    public string FullName { get; set; }
    public List<ImageViewModel> UserImages { get; set; }
}

// View model to represent user images
public class ImageViewModel
{
    public int ImageID { get; set; }
    public string ImageCaption { get; set; }
    public int NumOfLikes { get; set; }
    public string ImageFilePath { get; set; }
}
  1. Here's how to map to your view model. Simply create a new instance of your view model class(es) , assign the values to them and pass them to the view:

    [HttpGet]
    public ActionResult EditUser()
    {
        //
        // LOAD INFO ABOUT THE USER (Using a service layer, but you're probably just using Entity Framework)
        //
    
        // Get the user ID?
        var userId = this.User.Identity.GetUserId();
    
        // Get the user domain models from the database?
        var userDomainModel = this.UserService.GetUserInfo(userId);
    
        // Get the user's image domain models from the database?
        var userImagesDomainModelList = this.UserImageService.GetImagesForUser(userId);
    
        //
        // THE VIEW MODEL MAPPING STARTS HERE...
        //
    
        // Create an instance of your view model and assign basic info
        var responseModel = ProfileViewModel()
        {
            public string UserName = userDomainModel.UserName;
            public string Password = userDomainModel.Password;
            public string FullName = userDomainModel.FullName;
        }
    
        // Initialise list for images
        responseModel.UserImages = new List<ImageViewModel>();
    
        // Loop though each image domain model and assign them to the main view model
        foreach (var imageDomainModel in userImagesDomainModelList)
        {
             // Initialise image view model
             var imageViewModel = new ImageViewModel()
             {
                 ImageID = imageDomainModel.ImageID,
                 ImageCaption = imageDomainModel.ImageCaption,
                 NumOfLikes = imageDomainModel.NumOfLikes,
                 ImageFilePath = imageDomainModel.ImageFilePath
             };
    
             // Add the image view model to the main view model
             responseModel.UserImages.Add(imageViewModel);
        }
    
        // Pass the view model back to the view
        return View(responseModel);
    }
    
  2. Just map the incoming values that have been posted to your domain models in the same way:

    [HttpPost]
    public ActionResult UpdateImage(UpdateImageViewModel requestResponseModel)
    {   
        // Get the user ID?
        var userId = this.User.Identity.GetUserId();
    
        // Map incoming view model values to domain model
        var imageDomainModel = new Image()
        {
            ImageID = requestResponseModel.ImageId,
            ImageCaption = requestResponseModel.ImageCaption,
            NumOfLikes = requestResponseModel.NumOfLikes,
            ImageFilePath = requestResponseModel.ImageFilePath,
        }
    
        try
        {
            // Send the domain model up to your service layer ready to be saved
            this.UserImageService.UpdateImage(userId, imageDomainModel);
    
            ViewBag.SuccessMessage = "Your image was updated";
        }
        catch (Exception)
        {
            // Critical error saving user image
        }
    
        return View(requestResponseModel);
    }
    
  3. At no point will you try to attach your View Models to your Entity Framework context. If you did, then it would reject it. It knows which models it can accept by the IDbSet<object> properties that are defined within the definition of your DbContext:

    public class YourDbContext : DbContext
    {
        public YourDbContext() : ("YourDbConnectionStringName")
        {
        }
    
        // Definitions of valid Entity Framework objects
        public virtual IDbSet<User> Users { get; set; }
        public virtual IDbSet<Image> Images { get; set; }
    }
    
    var dbContext = new YourDbContext();
    
    var imageViewModel = new ImageViewModel();
    var imageDomainModel = new Image();
    
    // Adding object defined within your db context is fine...
    dbContext.Set<Image>().Add(imageDomainModel); // OK
    dbContext.Set<Image>().Add(imageViewModel); // Not OK, will result in exception
    

I personally don't sent Domain Models up to my service layer, I use DTOs (Data Transfer Objects). But that's a whole other story...

Please see this post from me that explains how I lay out my MVC applications: https://stackoverflow.com/a/32890875/894792

Upvotes: 1

Related Questions