How to correctly use a viewmodel - asp.net-mvc

I am new to ASP.net MVC. I am trying to create a viewmodel to display a join of data. Here is some example code:
public class Person
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public ICollection<Relative> Relatives { get; set; }
}
public class Relative
{
[Key]
public int ID {get; set; }
public Person Person { get; set; }
public RelationType RelationType { get; set; }
}
public class RelationType
{
[Key]
public int ID { get; set; }
public string Description { get; set; }
}
public class PersonViewModel
{
public string Name { get; set; }
public ICollection<string> RelativeNames { get; set; }
public ICollection<string> RelativeTypes { get; set; }
}
public class PersonContext : DbContext
{
public DbSet<PersonViewModel> people { get; set; }
}
When I try to create my controller through Visual Studio, I get the following error:
Unable to retrieve metadata for PersonViewModel. One or more validations errors were detected during generation:
EntityType 'PersonViewModel' has no key defined. Define the key for this EntityType.

The error is self explanatory. You need to add an Id field to the PersonViewModel which will have to be decorated with [Key] as you have rightly done in the classes above.

View Models are convenient classes for passing data between the controller and the view. The reason you are getting this exception is that because you are passing PersonViewModel class into your dbSet. You cannot do this unless PersonViewModel class has a corresponding table. In that case PersonViewModel should not be a view model but should be a entity,a model class to represent your table.
By Looking at your code I am guessing that you have tables for Person and Relative
in your database hence you shoud do the following
public class PersonContext : DbContext
{
public DbSet<Person> Person { get; set; }
public DbSet<Relative> Relative { get; set; }
}
and populate PersonViewModel through Person and Relative properties of your DbContext classes. This could be done inside the controller or in a repository class if you have one.

Related

Make foreign key to ApplicationUser in auxiliary table (EntityFramework Identity)

I have my ApplicationUser model defined like so:
public class ApplicationUser : IdentityUser
{
public virtual UserProfileInfo UserProfileInfo { get; set; }
}
With UserProfileInfo being an auxiliary table containing extra user data, defined as such:
public class UserProfileInfo
{
public int Id { get; set; }
public string SuperiorId { get; set; }
[ForeignKey("SuperiorId")]
public virtual ICollection<ApplicationUser> Superior { get; set; }
}
Each user has one or more people who are superior to them, in a business hierarchy. However, attempting to do a migration results in the following error:
The ForeignKeyAttribute on property 'Superior' on type 'Project.Models.UserProfileInfo' is not valid. The foreign key name 'SuperiorId' was not found on the dependent type 'Project.Models.ApplicationUser'.
How can I make a foreign key reference to ApplicationUser in my situation?
You need to do it the other way around, the ID is the foreignkey of the navigational property:
public class UserProfileInfo
{
public int Id { get; set; }
[ForeignKey("Superior")]
public string SuperiorId { get; set; }
public virtual ICollection<ApplicationUser> Superior { get; set; }
}

ASP.NET MVC create a view with a model class containing complex objects

I am trying to create a view (with Razor engine) by mapping the model class to Person class through the Add View option in Visual Studio 2013.
When it creates a view it only creates Age, Gender, Name fields. However, I need a view which would list down all the properties in each class; i.e. I need a view which contains the following fields: Age, Name, Gender, EmployerName, Salary, City, State, and Country.
I have a a class similar to this:
public class Person
{
public int Age { get; set }
public string Gender { get; set; }
public string Name { get; set; }
public JobDetails JobDetailsInfo { get; set; }
public Address AddressInfo { get; set; }
}
public class JobDetails
{
public string EmployerName { get; set; }
public string Designation { get; set; }
public int Salary { get; set; }
}
public class Address
{
public string City { get; set; }
public string State { get; set; }
public int Country { get; set; }
}
As your relationships are 1:1, this is pretty straight-forward.
You'll have to manually edit the view. Assuming the Model is of type Person, here's an example row:
<tr>
<td>#Model.Age</td>
<td>#Model.Name</td>
<td>#Model.Gender</td>
<td>#Model.JobDetailsInfo.EmployerName</td>
<td>#Model.JobDetailsInfo.Salary</td>
<td>#Model.AddressInfo.City</td>
<td>#Model.AddressInfo.State</td>
<td>#Model.AddressInfo.Country</td>
</tr>
This will work as long as you have that simple relationship, but if what you've shown does not correctly represent any normalisation you've applied to the data structure, this will fall flat on its face.
create the view manually or use inheritence...something like
public class jobdetails : person
{
}
I slightly changed my class structure and i created partial views for commondata,jobdetails and address and used them in my main view using #Html.Partial. I was able to pass default data by creating an object instance and loading some default values and passed the entire object to the view .The catch here is the model class which is bind to the Parent view must conatin all properties which are used for creating partial views. Pls see below
Controller method:
//Assign all properties for person object here
return View("ViewName", "PersonObject");
.cshtml:
#Html.Partial("ViewPath",Model.Data)
#Html.Partial("ViewPath",Model.JobDetailsInfo )
#Html.Partial("ViewPath",Model.AddressInfo )
public class Person
{
public CommonData Data
public JobDetails JobDetailsInfo { get; set; }
public Address AddressInfo { get; set; }
}
public class CommonData
{
public int Age { get; set }
public string Gender { get; set; }
public string Name { get; set; }
}
public class JobDetails
{
public string EmployerName { get; set; }
public string Designation { get; set; }
public int Salary { get; set; }
}
public class Address
{
public string City { get; set; }
public string State { get; set; }
public int Country { get; set; }
}

Entity Framework defining tables in db context

I am buys designing the model below:
public class LogModel
{
public class UserActivityLogs
{
[Key]
public int id { get; set; }
//Id of the user
public string userId { get; set; }
//Time of the log
public DateTime time { get; set; }
public LogActions action { get; set; }
}
// Types of actions to log
public class LogActions
{
[Key]
public int id { get; set; }
public string name { get; set; }
public string description { get; set; }
}
}
Now what I would like to know is do I need to add a table in the context for Logactions as well as UserActivityLogs or will EF see that the two tables are linked and create the log action table automatically?
Also have I specified my relationships correctly? What I was aiming for is that I can define multiple types of Logactions and then a userlog will then have a single log action associated to it.
First, don't use nested classes, it's a needless complication. Use namespaces to organize classes.
Second, don't use plural names for classes. One instance of class represents one entity. Also, use CamelCase names for properties.
Third, yes, Entity Framework will be aware of the associations between the two classes and create a database model with two tables and a foreign key.
So this leaves you with:
namespace MyApp.LogModel
{
public class UserActivityLog
{
[Key]
public int Id { get; set; }
public string UserId { get; set; }
public DateTime Time { get; set; }
public LogAction LogAction { get; set; }
}
public class LogAction
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
}

asp.net MVC 4 EntityType: EntitySet has no keys defined

I am a MVC newbie so go easy on me please.
I am getting two errors when I try to add a migration. They are as follows:
EntityType 'Icon' has no key defined. Define the key for this EntityType.
EntityType: EntitySet 'Icons' is based on type 'Icon' that has no keys defined.
I am including the Icon inside another model, like so:
public class Icon
{
public string IconName { get; set; }
public string IconColor { get; set; }
public int BackgroundXPos { get; set; }
public int BackgroundYPos { get; set; }
public string IconColorHover { get; set; }
public int BackgroundHoverXPos { get; set; }
public int BackgroundHoverYPos { get; set; }
}
public class GalleryThumbnail : CSSBoxModel
{
[DisplayName("Thumbnail Image Outline Color")]
public string ThumbnailImageOutlineColor { get; set; }
[DisplayName("Thumbnail Menu Font")]
public CSSFont ThumbnailMenuFont { get; set; }
[DisplayName("Thumbnail Icon Color")]
public Icon ThumbnailIconColor { get; set; }
}
How is this Address class below any different which is working:
public class Address
{
public String Adress1 { get; set; }
public String Adress2 { get; set; }
public String Adress3 { get; set; }
public String City { get; set; }
public String County { get; set; }
public String State { get; set; }
public String Zip { get; set; }
public String Country { get; set; }
}
[Table("UserProfile")] //Could be PP empolyee, Subscriber or Subscriber's customer
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public bool? Gender { get; set; }
public Address Address { get; set; } //billing address
public Address ShipAddress { get; set; }
}
I did not add a key in either my Icon or Address class because I have no intention of storing specific data in my DB. They are merely to be used inside other classes. So wy is one neededing an ID and the other is not?
I have not created public DbSet Icons { get; set; } in my DB Context either.
Also can you tell me what it is called when you use a class inside another ( or instance of class inside a class as in these examples ) ?
Much appreciated!
Since the address entity has no key defined it the Entity Framework assumes it's a complex property, and your UserProfile table will be rendered with columns named Addres_Address1, Address_Address2, Address_Address3, Address_City, and so on...
Even though you haven't declared an EntitySetIcons DbSet on your context class, it's still being added implicitly because one of your other classes somewhere has an ICollection or IEnumerable property defined.
More info on Code Conventions here:
http://msdn.microsoft.com/en-us/data/jj679962.aspx
So, either decorate the collections as NotMapped like #Kamyar said or simply remove the references from any class already declared as a DbSet.
you can use [NotMapped] attribute in System.ComponentModel.DataAnnotations.Schema namespace in EntityFramework.dll:
using System.ComponentModel.DataAnnotations.Schema;
...
[NotMapped]
public Address Address { get; set; } //billing address
[NotMapped]
public Address ShipAddress { get; set; }
Regarding the naming, AFAIK these are called public properties as well.

Display data from multiple models in one view

In the MVC 3 i want to display data from two models viz. Student and Enrollment into a single view.
Student model
public class Student
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int student_id { get; set; }
public string student_name { get; set; }
public string father { get; set; }
}
Enrollment model
public class Enrollment
{
[Key]
public int enrollment_id { get; set; }
public string rollno { get; set; }
public int student_id { get; set; }
public string registration_no { get; set; }
public date registration_date { get; set; }
}
My ViewModel looks like this
public class StudentEnrollmentViewModel
{
public Student_Info Student_Info { get; set; }
public Enrollment_Info Enrollment_Info { get; set; }
[Key]
public int ID { get; set; }
}
How do I retrieve the data from the two model and assign it to a viewmodel so that I can display it in a view? I am using Repository Design Pattern.
Generally speaking, a controller would be responsible for contacting the model, storing the result set returned in a variable/array/struc that the view would consume. The model and view components/classes would be registered in the controller.
An example:
<event-handler event="display.institutions" access="public">
<notify listener="userInstitutionRights" method="getInstitutionsWithDataRightsNOXML" resultKey="request.institutions" />
<view-page name="userNav" contentKey="request.userNav"/>
<view-page name="userInstitutions" contentKey="request.pageContent"/>
<announce event="assemblePage" />
</event-handler>
Event display.institutions is calling a model component userInstitutionRights and storing the result in a resultKey request.institutions and is including two view pages userNav, userInstitutions where the resultKey is available to each.
You can use DynamicPage, Look into following example
We need to use a Dynamic view page. (More Information)
Follow following steps:
Create DynamicViewPage type
public class DynamicViewPage : ViewPage
{
public new dynamic Model { get; private set; }
protected override void SetViewData(ViewDataDictionary viewData)
{
base.SetViewData(viewData);
Model = ViewData.Model;
}`
}
Your Controller will look like
public ActionResult Account(string returnUrl)
{
LoginModel loginmodel = null;//Initialize Model;
RegistrationModel registrationModel = null ;//Initialize Model;
// Any Extra logic
return View("Account", new
{
Login = loginmodel,
Register = registrationModel
});
}
your View should Inherit from
Inherits="DynamicViewPage"
Now #Model.Login will give you Loginmodel
#Model.Register will give you RegisterModel
It should work as you expected.........

Resources