MVC Viewmodel to display only model data - asp.net-mvc

This question is similar to this link:
ViewModel to display partial information
I am hoping for an example however. I've created my model, it looks like this:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace GuestListTemplate.Models
{
public class Guest
{
public int ID { get; set; }
[Required]
[Display(Name = "First Name:")]
public string FirstName { get; set; }
[Display(Name = "Last Name:")]
public string LastName { get; set; }
[DataType(DataType.EmailAddress)]
[Display(Name = "e-Mail:")]
public string eMail { get; set; }
[DataType(DataType.PhoneNumber)]
[Display(Name = "Phone #:")]
public string phone { get; set; }
public Boolean OptIn { get; set; }
[Display(Name = "Guest Last Name:")]
public string GuestLastName { get; set; }
[Display(Name = "Guest First Name:")]
public string GuestFirstName { get; set; }
[DataType(DataType.Currency)]
public decimal Donation { get; set; }
public int? Attended { get; set; }
}
}
All of this information is not neccesary for some views. I want to make a viewmodel to display only the first name, last name, donation and perhaps join the First and Last name. I am trying to do something like this but it doesn't work:
namespace GuestListTemplate.ModelViewModels
{
public class GuestViewModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public decimal Donation {get; set;}
[Display(Name = "Full Name")]
public string FullName
{
get { return FirstName + " " + LastName;}
}
}
}
How do I tell MVC to use the GUEST model as the source of data for this viewmodel, or how do I bind them together? (The purpose for this is I thought it might help performance of my application, Will it actually help performance??). I understand how to use Viewmodels to display data from multiple tables and pull in ALL data but in this case I want to pull only certain data from one table. Last, Is this better accomplished in the controller?
I hope this question makes sense. Would it be better to use a LINQ query such as
var Guests = db.Guest.Include(g => g.firstname, g.lastname, g.donation);
return (Guests.ToList());
(I understand the above command might not be exact syntax bbut you get the idea). If this is a better way to do it can someone demonstrate a basic way of doing this with the entire viewmodel code. I am pretty good with LINQ, so if someone offers a basic example I should be able to make it work for my purposes.
EDIT:
This worked for me (as well the interfaces outlined in the answer below):
ViewModel is the same as above.
Here is what I do in the controller:
var viewmodel = db.Guests.Select(g => new GuestListIndexData
{
ID = g.ID,
FirstName = g.FirstName,
LastName = g.LastName,
Donation = g.Donation,
Attended = g.Attended
}).OrderBy(g => g.FirstName);
return View(viewmodel.ToList());
My view is essentially the same as what I listed above as well. This works, but i'm not sure how much faster performance I am actually getting out of it so I probably won't use it until I am working with very large databases.

I was able to achieve this with interfaces, such as this:
public interface INameEntity
{
string FirstName { get; set; }
string LastName { get; set; }
}
And add this to Guest:
public class Guest : INameEntity
And use INameEntity in the partial:
#model INameEntity
#Html.TextBoxFor(i => i.FirstName)
This is the technique I use and it works great if Guest is your direct model in the parent view. If there is a parent model class, it's doable but a little more complex setup.

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)

How to search and load data in database by using a string keyword

This is my ProgramCategories model
public class ProgramCategories
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int id { get; set; }
public string courseCategory { get; set; }
}
This is my course information model.
public class CourseCategory
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[Required(ErrorMessage = "Please Select Field of Study")]
[Display(Name = "Field of Study")]
public string courseField { get; set; }
[Required(ErrorMessage = "Please Select Course Name")]
[Display(Name = "Course Name", Prompt = "Course Name")]
public string courseName { get; set; }
[Display(Name = "Attachments")]
public virtual ICollection<File> Files { get; set; }
public virtual ICollection<FilePath> FilePaths { get; set; }
}
The courseCategory in ProgramCategories is equals to courseField in CourseCategory. whenever saving course information i can select the category of course via dropdown. The dropdown contains all the ProgramCategories. I loaded all the programCategories(Ex:BankCourse, science course, etc) into index View.
All these things are working for the moment.
What I want to know is when i click one programCategory i want to display all of the courses in that category. Ex: if i select science course i want to get all the science courses.
This is how I would approach it...
public ActionResult CourseByCategory(string crsCtgry)
{
return View(getCourseByCategory(crsCtgry));
}
private List<CourseCategory> getCourseByCategory(string crsCtgry)
{
return db.CourseCategory.Where(n => n.courseField == crsCtgry).Select(n => n).ToList();
}
What you're describing is a one-to-many relationship, so handle it as such. Create a true foreign key between the two tables and then you can automatically pull in the course that belong to a category via either eager or lazy loading in Entity Framework:
public class ProgramCategories
{
...
public virtual ICollection<CourseCategory> Courses { get; set; }
}
public class CourseCategory
{
...
[ForeignKey("Category")]
public int CategoryId { get; set; }
public virtual ProgramCategories Category { get; set; }
}
Here I've used the primary key of ProgramCategories as the foreign key. You don't technically have to do it that way. You could still use a string as you're doing with courseField; you would just need to define a max length for the property:
[ForeignKey("Category")]
[MaxLength(50)]
public string CourseField { get; set; }
Otherwise, the property will be represented as an NVARCHAR(MAX) in the database, which can't be indexed (it's essentially the same as TEXT). However, best practice is to key off the primary key.
Also, your class naming is horrendous. Classes should be singular ProgramCategory vs. ProgramCategories, and your CourseCategory name doesn't actually describe what this class is. Seems Course would be more appropriate, as it looks like that's what you're actually defining here, but maybe courseName is another should-be-a-foreign-key scenario. When you name your classes and properties on those classes, you should be thinking about how you would read it. For example, "The course category course name is 'Foo'." makes no sense, but "The course name is 'Foo'." makes perfect sense. That would translate to something like:
public class Course
{
public string Name { get; set; }
}

Constructor for object model similar from entity

I'm trying my best to follow some MVC guidelines and for now, I have created a model with the fields I need from an entity I have. I have created the following Model class:
public class PersonStyle
{
public string Name { get; set; }
public int? Age { get; set; }
public string City { get; set; }
public string Style { get; set; }
}
My Entity is sometihng like:
public class PersonOE
{
public string Name { get; set; }
public int? Age { get; set; }
public string City { get; set; }
}
Im trying to build a constructor for the following:
PersonON personBus = new personBus();
List<PersonStyle> personStyleList = new List<PersonStyle>(personBus.getPeople()); //getPeople(); returns a PersonOE list
For this all, I need suggestions on how to create the PersonStyle constructor that will put "null" into the only different variable from the PersonOE model.
All you need to do is use LINQ to generate your properties. Though, adding your Style to each of them could get a little harder to deal with, but you haven't given any input on where they're coming from. This is a quick and easy way to convert from your data to model objects.
List<PersonStyle> personStyleList = personBus.GetPeople()
.Select(p => new PersonStyle {
Name = p.Name,
Age = p.Age,
City = p.City
});

ASP.NET MVC - create a new Model or use a Entity framework class

I am developing a ASP.NET MVC 3 application, i am using entity framework code first in order to create the classes of my app, and i also have a repository in order to perform the operations on it, keeping clean the DBContext and the DBEntities definitions.
My doubt is about the render of the views and the way where a edit model is saved.
If I have this entity that represent a user stored in my DB:
//Entity:
public class User
{
[Key]
public int IdUser { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
}
And i want to show a View with the FirstName, LastName, Email and NewPassword, ConfirmPasword and CurrentPassword, in order to let the user change his data, typing the CurrentPassword to confirm the changes, so my doubt is, fieds like ConfirmPasword and CurrentPassword aren´t in my entity so i need to create a new model for this View and the copy the information that i want from my new Model to my database entity in order to save it? Like:
public class UpdateUserModel
{
[Required]
[Display(Name = "Name")]
public string FirstName{ get; set; }
[Required]
[Display(Name = "Last Name")]
public string LastName{ get; set; }
[Required]
[DataType(DataType.EmailAddress)]
[Display(Name = "Not valid email")]
public string Email { get; set; }
[DataType(DataType.Password)]
[Display(Name = "New password")]
public string NewPasword{ get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm the New Pasword")]
[Compare("NewPasword", ErrorMessage = "Password doesn´t mach.")]
public string ConfirmPasword{ get; set; }
[Required(ErrorMessage = "Need to specify the current password to save changes")]
[DataType(DataType.Password)]
[Display(Name = "Current Password")]
public string CurrentPassword { get; set; }
}
and in the controller i made:
public ActionResult UpdateUser(UpdateUserModel model)
{
User u = (User)Membership.GetUser();
u.FirstName = model.FirstName;
u.LastName = model.LastName;
u.Email = model.Email;
if (!String.IsNullOrEmpty(model.NewPassword))
{
u.Password = FormsAuthentication.HashPasswordForStoringInConfigFile(model.NewPassword.Trim(), "md5");
}
repository.UpdateUser(u);
return View();
}
There are any way of doing this having a controller like:
public ActionResult UpdateUser(User u)
{
repository.UpdateUser(u);
return View();
}
Because if i have that, how i can add the field like, ConfirmPassword or CurrentPassword in order to made the validation for this specific View.
If I were you, I wouldn't use domain model in my presentation layer. I would create a view model (another class) which will be very similar to my domain model. I would then use auto-mapping tool to map from my domain model to the view model.
This is a very common scenario, so if you Google for "view and domain" models you should find everything you need.
public class User {
[Key]
public int IdUser { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
}
public class UpdateUserViewModel {
// Original fields
public string Password { get; set; }
public string PasswordConfirmation { get; set;
}
You could then configure auto-mapper to remove your boiler plate code:
public ActionResult ShowUser()
{
var domainModel = new User(); // I'm assuming that properties are set somewhere
var viewModel = new UserViewModel();
Autommaper.Map(domainModel, viewModel);
return View(viewModel);
}
This is very rough, but hopefully you get an idea.
Update 1: **
As i understood is better to create a new model for each view and then map it into the entity
It's not just better, it provides better separation of concerns, makes your code easily testable. Just by looking at the name of the class, I can see its purpose UpdateUserViewModel, RegisterUserViewModel etc).
Original fields, in this class is supposed to be the Metadata with the validation and that stuff isn't?
By original fields I mean:
public class UserViewModel{
public string UserName { get; set; }
public string FirstName { get; set; }
}
These fields are already in your User class, so I saved my time by not typing them in again.
This will be change my model from MVC to MVVM or not beacuse i still have a controller?
I believe what I've suggested is still an MVC pattern, rather than MVVM.
About the Automaper, are you using github.com/AutoMapper/AutoMapper?
Automapper is something that I have used. There are few tools out there and they do pretty much the same thing. Try out few and find one that suits your requirements the most.
Good luck.
Usually I use areas for different parts of my project, as an aside of where to put this extra code.
Pretty much you are going to add to your model folder a viewmodel.cs class. Inside this class will hold your definitions for how the data will be modelled in the view. These viewmodels will reflect the parts of the entity you wish the user to interact with. The interaction will be done in the controllers via [HttpGet] where you pass in the view model to be interacted with, and [HttpPost] where you send the model back and then map it to an entity.
ViewModels.cs:
public class UserViewModel
{
public string UserName { get; set; }
}
SomeController:
public ActionResult getView()
{
var uvm = new UserViewModel();
return View(uvm);
}
View getView.cshtml:
#model project.namespace.UserViewModel
#using (Html.BeginForm())
{
#Html.EditorFor(m => m.UserName)
<input type="submit" value="New User Name" />
}
Back in controller:
[HttpPost]
public ActionResult getView(UserViewModel model)
{
var entity = new ActualEntity();
entity.username = model.UserName;
//more mapping
//commit changes somewhere
return RedirectToAction("getView");
}

ASP MVC 3.0 Complex View

I am developing a application for Sales Order Management using ASP.NET MVC 3.0. I need to develop a page where Customer Details can be added.
Customer Details Include
public class Customer
{
public int ID { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public string Alias { get; set; }
public int DefaultCreditPeriod { get; set; }
public Accounts Accounts { get; set; }
public IList<Address> Addresses { get; set; }
public IList<Contact> Contacts { get; set; }
}
public class Accounts
{
public int ID { get; set; }
public string VATNo { get; set; }
public string CSTNo { get; set; }
public string PANNo { get; set; }
public string TANNo { get; set; }
public string ECCNo { get; set; }
public string ExciseNo { get; set; }
public string ServiceTaxNo { get; set; }
public bool IsServiceTaxApplicable { get; set; }
public bool IsTDSDeductable { get; set; }
public bool IsTCSApplicable { get; set; }
}
public class Address
{
public int ID { get; set; }
public AddressType Type { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public string Line3 { get; set; }
public string Line4 { get; set; }
public string Country { get; set; }
public string PostCode { get; set; }
}
public class Contact
{
public int ID { get; set; }
public ContactType Type { get; set; }
public string Name { get; set; }
public string Title { get; set; }
public string PhoneNumber { get; set; }
public string Extension { get; set; }
public string MobileNumber { get; set; }
public string EmailId { get; set; }
public string FaxNumber { get; set; }
public string Website { get; set; }
}
Customer Requires a single page to fill all the customer details(General info, Account Info,Address Info and Contact Info). There will be multiple Addresses(Billing, Shipping, etc) and multiple Contacts (Sales, Purchase). I am new to MVC. How to Create the View for the above and Add multiple Address dynamically?
I often create wrapper models to handle this kind of situation e.g.
public class CustomerWrapperModel
{
public Customer Customer { get; set;}
public Accounts Accounts { get; set;}
public List<Address> AddressList { get; set}
//Add
public CustomerWrapperModel()
{
}
//Add/Edit
public CustomerWrapperModel(Customer customer, Accounts accounts, List<Address> addressList)
{
this.Customer = customer;
this.Accounts = accounts;
this.AddressList = addressList;
}
}
then declare the View to be of type CustomerWrapperModel and use editors like so:
#model MyNamespace.CustomerWrapperModel
#Html.EditorFor(model => model.Customer)
#Html.EditorFor(model => model.Accounts)
#Html.EditorFor(model => model.AddressList)
and have a controller to receive the post that looks like this:
[HttpPost]
public ActionResult(Customer customer, Accounts accounts, List<Address> addressList)
{
//Handle db stuff here
}
As far as adding addresses dynamically I found the best way to do this if you're using MVC validation and want to keep the list structured correctly with the right list indexes so that you can have the List parameter in your controller is to post the current Addresses to a helper controller like this:
[HttpPost]
public PartialResult AddAddress(List<Address> addressList)
{
addressList.Add(new Address);
return PartialView(addressList);
}
then have a partial view that just renders out the address fields again:
#model List<MyNamespace.Address>
#{
//Hack to get validation on form fields
ViewContext.FormContext = new FormContext();
}
#Html.EditorForModel()
make sure you address fields are all in one container and then you can just overwrite the existing ones with the returned data and your new address fields will be appended at the bottom. Once you have updated your container you can do something like this to rewire the validation:
var data = $("form").serialize();
$.post("/Customer/AddAddress", data, function (data) {
$("#address-container").html(data);
$("form").removeData("validator");
$("form").removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse("form");
});
NB. I know some people with have an issue with doing it this way as it requires a server side hit to add fields to a page that could easily just be added client side (I always used to do it all client side but tried it once with this method and have never gone back). The reason I do it this way is because it's the easiest way to keep the indexes on the list items correct especially if you have inserts as well as add and your objects have a lot of properties. Also, by using the partial view to render the data you can ensure that the validation is generated on the new fields for you out of the box instead of having to hand carve the validation for the newly added client side fields. The trade off is in most cases a minor amount of data being transferred during the ajax request.
You may also choose to be more refined with the fields you send to the AddAddress controller, as you can see I just post the entire form to the controller and ignore everything but the Address fields, I am using fast servers and the additional (minor) overhead of the unwanted form fields is negligible compared to the time I could waste coding this type of functionality in a more bandwidth efficient manner.
You pass your root model object to the View call in your controller like this:
public ActionResult Index() {
var customer = GetCustomer(); // returns a Customer
return View(customer);
}
And then your view looks something like this:
#model Customer
<!DOCTYPE html>
<!-- etc., etc. -->
<h1>Customer #Model.Name</h1>
<ul>
#foreach (var address in Model.Addresses) {
<li>#address.Line1</li>
}
</ul>
One gets the picture.
The code above depends on the #model directive, which is new in ASP.NET MVC 3 (see this blog post).
Is a good question :D for normal navigation properties such as Accounts doing this is not to hard:
#Html.EditorFor(model => model.Accounts.ID)
#Html.EditorFor(model => model.Accounts.VATNo)
will do something you want. But for collection navigation properties (Addresses and Contacts) you can't do this in one place by default. I suggest you use a different page for Addresses (and one for Contacts). Because it is the easiest way. But if you want to do this in one place (and also with out AJAX requests), you can create view by Customer, use scaffolding for model and it's simple navigation properties, and for lists (Addresses, Contacts) you must add them with JavaScript to the input fields (for example for each Address added, put it in an Array) and post fields to server. At server you can get main model and simple properties by default model-binder and for lists, you can 1) create your own model binder 2) parse them from inputted strings by yourself. Good lock

Resources