Create ViewModel in order to combine 2 models linked - c#

As a newbie with ASP.NET MVC pattern, I'm trying to create a small web application in order to practice knowledge learned through some tutorials.
I have some obscure things about Model and ViewModel. I understand that Model defined only the table structure whereas ViewModel defined the logic for data, How to handle data... Furthermore, ViewModel is used when I want to display more than one model into my View.
Well, it's very theoretical and I'm trying to develop this with my application.
My application:
This application lets to handle projects and people. I can create a new project object containing some properties: project name, project location, ... and add a list of people who will work on this specific project.
Then, in the other side, I have a simple people table with properties like : Firstname, Lastname and function.
When I create a new project, I would like to select one or multiple people in order to attach them to the project.
My class People:
I created a simple class which looks like this:
public class People
{
public int PeopleID{ get; set; }
public string Lastname { get; set; }
public string Firstname { get; set; }
public string Job{ get; set; }
}
I removed Annotations in order to see clearer my class.
I created the CRUD associated and it works fine.
My class Project:
In this class, I define properties from project object and I would like add a list of people collaborating on the project.
I have:
public class Project
{
public int ProjectID { get; set; }
public string ProjectName{ get; set; }
public string ProjectLocation{ get; set; }
public List<People> ListOfPeople { get; set; }
}
If I understand, now I have to create a ViewModel in order to create my Project object with information from Project and People classes ?
My class ProjectPeopleVM:
This class is identical as Project class ?
So I have:
public class ProjectPeopleVM
{
public int ProjectID { get; set; }
public string ProjectName{ get; set; }
public string ProjectLocation{ get; set; }
public List<People> ListOfPeople { get; set; }
}
Is it right ? I have some doubts about this.
If I want to create a controller class which let to Create a new object Project, I have to fill the ListOfPeople by using EF ? Something like db.People.ToList() ?
public class ProjectsController : Controller
{
private MyAppContext db = new MyAppContext();
public ActionResult Create()
{
var people_list = db.People.ToList();
var project = new ProjectPeopleVM
{
ListOfPeople = people_list;
// What I need to add here ? Data to populate ListOfPeople come from people_list variable
}
return View(project);
}
I'm a bit lost.

It's not necessary that you create a duplicate of your class just to see the information but it seems that in your code, you might need to because;
I noticed that in your Project Model, you didn't use public virtual List<People> or the virtual keyword, which is used for "lazy loading". When an existing project is taken from the db context, if you have the virtual keyword on your property, then it would automatically load the associated object. On the other hand, if you don't have it, then you will need to manually assign the list. Using lazy loading might have a little effect on the performance but with this you can view the properties of your child class immediately.
If your list has virtual property,
public class Project
{
public int ProjectID { get; set; }
public string ProjectName{ get; set; }
public string ProjectLocation{ get; set; }
public virtual List<People> ListOfPeople { get; set; }
}
Then in your controller or view, you could navigate to the properties of the objects in that list;
// this will give the first name of the first person on the first project
db.Project.FirstOrDefault().ListOfPeople.FirstOrDefault().FirstName;
For your create action in your controller, since it's a new Project, it doesn't have any People in it. Hence you will need to manually populate that list. To populate it, since you only need specific people, I suggest to use a checkbox or multiple input fields (aided with javascript).
The ListOfPeople can be populated by having a form element;
<input name="ListOfPeople[1].PeopleId" value="1"/>
<input name="ListOfPeople[1].FirstName" value="Mark"/>
<input name="ListOfPeople[1].LastName" value="Jacob"/>
<input name="ListOfPeople[1].PeopleId" value="2"/>
<input name="ListOfPeople[2].FirstName" value="Red"/>
<input name="ListOfPeople[2].LastName" value="Wandersee"/>
When you submit the form, the values will be bound to the Project model's ListOfPeople. Then that's the time you will need to loop through it and create a ProjectPerson (junction) record which determines where this person belongs to.
foreach(var i in model.ListOfPeople){
ProjectPerson pp = new ProjectPerson();
... // do property assignment
db.ProjectPerson.add(pp);
}

your view models should be used to map a combination of data drawn from the db. i.e.
public class Project
{
public int ProjectID { get; set; }
public string ProjectName{ get; set; }
public string ProjectLocation{ get; set; }
public IColleciton<People> ListOfPeople { get; set; }
}
public class People
{
public int Id{ get; set; }
public string Name{ get; set; }
public virtual Project project { get;set; }
}
this will allow relational retrieval from EF
viewModel should be used when you need a combination of this data without relationship i.e.
public class Project
{
public int ProjectID { get; set; }
public string ProjectName{ get; set; }
public string ProjectLocation{ get; set; }
}
public class People
{
public int Id{ get; set; }
public string Name{ get; set; }
}
public class ProjectVm
{
public int ProjectID { get; set; }
public string ProjectName{ get; set; }
public string ProjectLocation{ get; set; }
public ICollection<People> ListOfPeople { get; set; }
}
you can use a tool such as automapper to set up the mapping between objects which will generate custom model inside controller.
see this article: http://bengtbe.com/blog/2009/04/14/using-automapper-to-map-view-models-in-asp-net-mvc/
and DB Relationships
https://learn.microsoft.com/en-us/ef/ef6/modeling/code-first/conventions/built-in

Related

Deriving a database model for view model in ASP.MVC

I am creating some view models for my ASP MVC web app.
I created "code first" models for database. Is it a good way to derive view models from database models?
Example database model:
public class Project
{
[Key]
public int Id { get; set; }
public int? CustomerId { get; set; }
public int TypeId { get; set; }
public string Number { get; set; }
public string Name { get; set; }
}
View model:
public class ViewModelProject : Project
{
[NotMapped]
public DateTime? Start { get; set; }
[NotMapped]
public DateTime? End { get; set; }
[NotMapped]
public string Manager { get; set; }
}
Is this the right way or is it completely false?
EDIT (subquestion):
I have some very simple database models like ProjectType, which only contains i.e. two properties. Should I also fragment those models in model view or can I make it that way:
Simple database model:
public class ProjectType
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int? Code { get; set; }
}
Can I use it like so:
public class ProjectVM
{
public string Name { get; set; }
public int Number { get; set; }
public ProjectType Type { get; set; }
}
Or does it have to be fragmented like so:
public class ProjectVM
{
public string Name { get; set; }
public int Number { get; set; }
public string Type { get; set; }
public int TypeCode { get; set; }
}
I would not recommend doing it this way. I (and many others) have tried it and it doesn't work well. You will inadvertedly run into troubles, since an MVC model has to be tailored to the view and what you get from the DB rarely fits. Sure, you can hammer it into place, but the code quickly gets messy and store-related and UI code starts to mangle together. This even shows in your example, since you have to put the NotMappedAttribute (which is related to data storage), to ViewModelProject (a class at UI level).
There are many other examples to show this problem, but an especially good one I find when you want to serialize a model object to JSON and send it to a JavaScript client. The JSON serializer takes the values of all public properties and adds them to the JSON. If you want to exclude a property, you have to mark it with a ScriptIgnoreAttribute, which you would also have to apply to the base class, which breaks separation between UI and store-related code.
The better way to go is to keep the staorage model and the MVC model separated and to map the data from one to the other (there are already pre-existing frameworks that help you with that, such as Automapper). This comes with additional advantages, for example better testability, since you are now not dependent on a specific data store to create model instances.

CRUD Operations on Grandchild using MVC

This is my first question on this community, I hope someone can help.
I have 3 models: Parent, child and grandchild. Resource, Parameter and Metric. I create the controlers with entity framework and it generated all CRUD operations. My problem its basically the grandchild. When I go to create a new Metric (grandchild), I have the dropdownlist of all the Parameters (child), but I want first to choose the Resource, then that will list all the parameters from that resource so I can create the metric. I'm new on asp MVC and this might be a lil bit basic question but I couldn't find anything like this. Thanks
Here are my classes just in case.
public class Resource
{
public int ResourceID { get; set; }
public string Name { get; set; }
public virtual ICollection<Parameter> Parameters { get; set; }
}
public class Parameter
{
public int ParameterID { get; set; }
public string Name { get; set; }
public int ResourceID { get; set; }
public virtual Resource Resource { get; set; }
public virtual ICollection<Metric> Metrics { get; set; }
}
public class Metric
{
public int MetricID { get; set; }
public string Name { get; set; }
public int ParameterID { get; set; }
public virtual Parameter Parameter { get; set; }
}
What you are trying to do sounds like either a linked or cascading drop down list. I did a quick search and found this link that may help you.
You will need some JavaScript that listens to the selection changed event for the first list (parent), and then updates the second list (child) with the available values. Depending on your situation, you may then need to link the third list (grandchild) to load when the second list has its selection changed as well.

Multiple Model In MVC

I am learning how to use MVC right now and I just have a question on when I am creating and updating entries in the database. I was reading a post from this page: asp.mvc 4 EF ActionResult Edit with not all fields in view
The guy in it said to create a model that will be used, so is the efficient way to insert a new row and update an existing row by having two models with different properties?
So my models would look like this -
public class UserModelView
{
public string FirstName { get; set; }
public string Surname { get; set; }
public DateTime AccountCreated { get; set; }
public DateTime? LastLoggedIn { get; set; }
}
public class UserModelCreate
{
[Key]
public int UserId { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
public DateTime AccountCreated { get; set; }
}
public class UserModelUpdate
{
public string FirstName { get; set; }
public string Surname { get; set; }
public DateTime? LastLoggedIn { get; set; }
}
Is this the best way to do what I need to do?
Im guessing you were previously using the entity class when binding your model back in.
You shouldn't do that!
The guy in the post is right, this is a much better way of controlling your entity and model information and provides a layer of seperation between the two.
After all you wouldnt want a user being able to directly manipulate an entity via a HTTP request.
I answered something similar here

How to use TinyMCE with entity framework entities

I have entity class in created using entity framework which is in my Domain project
using System;
using System.Collections.Generic;
public partial class Test
{
public int Id { get; set; }
public int ExamID { get; set; }
public string TestName { get; set; }
public string StartDescription { get; set; }
public string EndDescription { get; set; }
}
And In my MVC application I am creating one viewmodel which I use in my view
public class TestViewModel
{
public Test Test { get; set; }
}
Now I want to make fields related to "StartDescription" and "EndDescription", for this is am trying to use TinyMCE.
Now the problem is "[AllowHtml]" attribute is in mvc but my real entity is in other project
I am following this tutorial.
http://www.codeproject.com/Articles/674754/TinyMCE-and-ASP-NET-MVC-advanced-features
Rather than your view model having an instance of Test it should contain the properties you wish to use in the view. You can then add the [AllowHtml] attribute to the properties in your view model without affecting your domain objects.
public class TestViewModel
{
public int Id { get; set; }
[AllowHtml]
public string StartDescription { get; set; }
[AllowHtml]
public string EndDescription { get; set; }
}
In your controller you would then need to map the view model to your domain class.
Old post but thought this might be relevant for someone else:
borrowing a sample code from petelids and modifying it.
public class TestViewModel
{
public int Id { get; set; }
[UIHint("tinymce_jquery_full"), AllowHtml]
public string StartDescription { get; set; }
[UIHint("tinymce_jquery_full"), AllowHtml]
public string EndDescription { get; set; }
}
Providing the UIHint on the model object you can place your tinyMCE script code in a file saved in the Folder
~/Views/Shared/TemplateEditor
I do this using the TinyMCE4.MVC libraries - however mine is modified a bit for my own special workings that I have added.

C# Entity Framework and Business Logic

I have a database and I'm accessing it via EF.
public partial class Project
{
public int ProjectID { get; set; }
public string Name { get; set; }
public virtual ICollection<ProjectAssets> ProjectAssets { get; set; }
}
public partial class ProjectAssets
{
public int MappingID { get; set; }
public int ProjectID { get; set; }
public int AssetID { get; set; }
public virtual Project Project { get; set; }
public virtual Asset Asset { get; set; }
}
public partial class Asset
{
public int AssetID { get; set; }
public string Name { get; set; }
public short Type { get; set; }
public virtual ICollection<ProjectAssets> ProjectAssets { get; set; }
}
So, my program have only 1 active Project in the time.
I want to be able to bind to Project and display as a tree or some other way all Assets and I want to be able to create new Asset or add existing Asset what belongs to other project.
If I will use the generated entities I would not be able to manage that all so I need some rules. I've already found good impl. of repositories, but still don't know how to create rules.
Do I need to create something like:
public class WorkProject : Project
{
public WorkProject(Project projject){...}
WorkAsset CreateAsset(){...}
void AddAsset(Asset asset){...}
}
As far as I understand your question, you want to control the graph of entities which are related to a project object. You can leave the repository layer intact and put another layer (business layer) on top of it to enforce the rules.

Categories