Trying to make a simple application but my view returns nothing when trying to use a viewmodel. I assume the "db.[TableName].ToList();", which works when applied on a domain model, is not enough and the selection should happen in a different way when using a viewmodel, but I have no idea how to do it. Please help. Thank you.
Town.cs
using System.Collections.Generic;
namespace City.Models
{
public class Town
{
public Town()
{
Streets = new List<Street>();
}
public int TownId { get; set; }
public string TownName { get; set; }
public virtual ICollection<Street> Streets { get; set; }
}
}
Street.cs
using System.Collections.Generic;
namespace City.Models
{
public class Street
{
public Street()
{
Houses = new List<House>();
}
public int StreetId { get; set; }
public string StreetName { get; set; }
public virtual ICollection<House> Houses { get; set; }
}
}
House.cs
namespace City.Models
{
public class House
{
public int HouseId { get; set; }
public string HoueseName { get; set; }
public int StreetId { get; set; }
public virtual Street Street { get; set; }
}
}
Floor.cs
namespace City.Models
{
public class Floor
{
public int FloorId { get; set; }
public int FloorNumber { get; set; }
public int FireExtinguisherId { get; set; }
}
}
FireExtinguisher.cs
namespace City.Models
{
public class FireExtinguisher
{
public int FireExtinguisherId { get; set; }
public string FireExtinguisherName { get; set; }
public int FloorId { get; set; }
}
}
MyViewModel.cs
namespace City.Models
{
public class MyViewModel
{
public MyViewModel()
{
Town = new Town();
Street = new Street();
House = new House();
Floor = new Floor();
FireExtinguisher = new FireExtinguisher();
}
public int MyViewModelId { get; set; }
public Town Town { get; set; }
public Street Street { get; set; }
public House House { get; set; }
public Floor Floor { get; set; }
public FireExtinguisher FireExtinguisher { get; set; }
}
}
ApplicationDbContext.cs
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public DbSet<Town> Towns { get; set; }
public DbSet<Street> Streets { get; set; }
public DbSet<House> Houses { get; set; }
public DbSet<Floor> Floors { get; set; }
public DbSet<FireExtinguisher> FireExtinguishers { get; set; }
public DbSet<MyViewModel> MyViewModels { get; set; }
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
HomeController.cs (I think the problem lies here)
using System.Linq;
using System.Web.Mvc;
using City.Models;
namespace City.Controllers
{
public class HomeController : Controller
{
private ApplicationDbContext db;
public HomeController()
{
db = new ApplicationDbContext();
}
public ActionResult Index()
{
return View(db.MyViewModels.ToList());
}
public ActionResult About()
{
ViewBag.Message = "Your application description page.";
return View();
}
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
}
}
Index.cshtml
#model IEnumerable<City.Models.MyViewModel>
<h2>Map information</h2>
<div class="container">
<table class="table">
<thead>
<tr>
<th>Town</th>
<th>Street</th>
<th>House</th>
<th>Floor</th>
<th>FireExtinguisher</th>
</tr>
</thead>
#foreach (var item in Model)
{
<tbody>
<tr>
<td>#(item.Town.TownName)</td>
<td>#(item.Street.StreetName)</td>
<td>#(item.House.HoueseName)</td>
<td>#(item.Floor.FloorNumber)</td>
<td>#(item.FireExtinguisher.FireExtinguisherName)</td>
</tr>
</tbody>
}
</table>
</div>
Even though I have test data in the db, this is all what I see when I run it:
Image is here
Please tell me what should I fix, how to get data retrieved. Thanks
EDIT #CrowdCoder
new picture here
I think your understanding about view model is incorrect.
View model is a class to transfer data between your view and your action method. View model is specific to the view. So if your view needs to display only 2 properties (Name and Age), your view model will have only those 2 properties. No need to bring all the properties from your entity model to the view model class.
I see that you added a new collection to the your db context,
public DbSet<MyViewModel> MyViewModels { get; set; }
This does not makes any sense. As i mentioned earlier, view models are UI concerns. It should not be in your data access code. Also do not mix the entities created by your ORM layer in your view model.
Also view models are simple POCOs. It should be lean-flat classes with properties. It is your responsibility to load the property values. You can do that in your action method or another method called from your action method.
Let's say you want to display a list of houses with it's street name, you will create a view model like this
public class HouseViewModel
{
public int HouseId { set; get;}
public string HoueseName { set;get;}
public string StreetName { set;get; }
}
Now in your view, you simply access these properties
#model IEnumerable<HouseViewModel>
<table>
#foreach(var item in Model)
{
<tr>
<td>#item.HouseId </td>
<td>#item.HoueseName </td>
<td>#item.StreetName </td>
</tr>
}
</table>
Ofcourse, for this code to work, you need to make sure you will be creating a list of HouseViewModel and send it to the view from your action method.
public ActionResult Index()
{
var list= new List<HouseViewModel>{
new HouseViewModel { HouseId =1,HoueseName ="Abc", StreetName ="Detroit"},
new HouseViewModel { HouseId =2,HoueseName ="Xyz", StreetName ="Novi"}
};
return View(list);
}
Now you can see that how we are using view model to transfer data from the action method to the view. Here we just hard coded the property values for the items in the list we are sending. We can update that to read from your EF db context as needed.
Let's read all the Houses, use LINQ projection to create a HouseViewModel object for each item in that collection and assign the property values.
public ActionResult Index()
{
var houses = db.Houses
.Select(a=>new HouseViewModel
{ HouseId =a.HouseId,
HoueseName =a.HouseName,
StreetName = a.Street.StreetName
})
.ToList();
return View(houses);
}
Related
I'm trying to use two tables in the same View in my asp.net mvc project but I'am doing some errors and I get this error:
System.InvalidOperationException: The model item passed into the dictionary is of type 'System.Data.Entity.Infrastructure.DbQuery1[Question], but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable1[projet.Models.userdbcontext]
Class Questions.cs:
public class Question
{
public int Id { get; set; }
public int userID { get; set; }
}
Class User.cs:
public class User
{
public int Id { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string Name { get; set; }
}
Model userdbcontext.cs:
{
public userdbcontext()
{ }
public DbSet<Question> Questiondb { get; set; }
public DbSet<User> Usersdb { get; set; }
}
and this is the controller:
private userdbcontext db = new userdbcontext();
// GET: question
public ActionResult Index()
{
var l = from e in db.Questiondb
select e;
return View(l);
}
The view:
#model IEnumerable<projet.Models.userdbcontext>
your error is that you are trying to send a DbSet<> to the view which is hard to manipulate so to solve the problem, you have to create a new class ViewModel in which you store the value of the DbSet<> as List<> then you pass it to the View like this :
Model userdbcontext.cs:
public class userdbcontext : DbContext
{
public userdbcontext()
{ }
public DbSet<Question> Questiondb { get; set; }
public DbSet<User> Usersdb { get; set; }
}
public class ViewModel
{
public List<Question> Question { get; set; }
public List<User> User { get; set; }
}
In the controller:
private userdbcontext db = new userdbcontext();
// GET: question
public ActionResult Index()
{
var l = new ViewModel();
l.Question = db.Questiondb.ToList();
l.User = db.Usersdb.ToList();
return View(l);
}
and in the view:
#model projet.Models.ViewModel
You have to create a view model:
public class ViewModel
{
public List<Question> Questions { get; set; }
public List<User> Users { get; set; }
}
action
public ActionResult Index()
{
var vm = new ViewModel{
Questions = db.Questiondb.ToList(),
Users= db.Userdb.ToList()
}
return View(vm);
}
view
#model projet.Models.ViewModel
....
<!-- Accessing Model Variables -->
#Model.Questions...
#Model.Users...
I used scaffolding to create the Index, Details, Create, Edit and Delete views and the controller. I have two view models (Parent / Child) relation. In my Index view I want to display the list of Teams as well as some information on the players (Parent / child). For example I want to display in the Index view the teams with the players count per team and last players that was modified. I am not sure where to begin.
Example:
(Team) Red -- (Last Modified) 01/02/2015 -- (Number Players) 10 and so on.
Team ViewModel
public class TeamVM
{
public int ID { get; set; }
public string Name { get; set; }
public DateTime? LastActivity { get; set; }
public string NumberPlayers { get; set; }
public IList<PLayerVM> PlayerVM { get; set; }
}
Player ViewModel
public class PlayerVM
{
public int ID { get; set; }
public int TeamID { get; set; }
public string PlayerInfo { get; set; }
public DateTime? CreateDate { get; set; }
}
Other ViewModel
public class TeamViewModel
{
public List<Team> Teams{ get; set; }
}
Controller
public ActionResult Index()
{
TeamViewModelviewModel = new TeamViewModel();
viewModel.Teams= db.Teams.ToList();
return View(viewModel);
}
db.Products.ToList()?? I assume that is where you mean db.Teams.ToList()?
You are using viewmodels, so you should map the db data to your viewmodels first:
public ActionResult Index()
{
var teams = db
.Teams
.Include("Players") // Assuming your Team entity has a collection of Players
.SelectMany(t => new TeamVM {
ID = t.ID,
// etc..
})
.ToList();
return View(new TeamViewModel { Teams = teams });
}
model:
public class TeamVM
{
public int ID { get; set; }
public string Name { get; set; }
public DateTime? LastActivity { get; set; }
public IList<PLayerVM> PlayerVM { get; set; }
public int NumberPlayers {
get { return PlayerVM.Count(); }
}
}
Then in your view:
#model MyProject.Models.TeamViewModel
<table>
#foreach(var team in Model.Teams.ToList()) {
<tr>
<td>#team.Name</td> // Name
<td>#team.NumberPlayers</td> // Playercount
<td>#team.PlayerVM.Max(p => p.LastActivity).LastActivity</td> // Last edited
</tr>
}
</table>
I have 3 models names images,game and imageviewmodel
public class game
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public string Name { get; set; }
public virtual ICollection<images> Image { get; set; }
}
public class images
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
[DataType(DataType.ImageUrl)]
public string Image1Url { get; set; }
public virtual game Game { get; set; }
}
public class ImageViewModel
{
[Required]
[DataType(DataType.Upload)]
public HttpPostedFileBase ImageUpload { get; set; }
public virtual game Game { get; set; }
}
public class GameDb : DbContext
{
public DbSet<game> Games { get; set; }
public DbSet<images> Images { get; set; }
}
My view is strongly typed view of imageviewmodel . I have a dropdown list there with all games filled Here is my GET create method
public ActionResult Create()
{
ViewBag.GameId = new SelectList(db.Games, "Id", "Name");
return View(new ImageViewModel());
}
my dropdown is filled with GenreId
<div class="editor-field">
#Html.DropDownList("GameId","Select an Item")
</div
On my POST create method I want to access dropdown value id to insert in image table
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ImageViewModel model)
{
}
I am unable to access game id of drop down list.I am doing like this
var img=new images{
Game.( no intellisense) =model.Game.id,
};
How do I resolve that need some help.
First of all consider follow the naming convensions when you name your classes.
Second, consider using DropDownListFor helper method instead of DropDownList
And finally you have to create new Game object instance before set it's id:
var img = new images
{
Game = new game { Id = model.Game.Id }
};
I'm trying to get 2 models to show in 1 view but it is not working. I have tried lots of different ideas from Google but none have worked so far.
There is no error in the Error List. But when I start it I get this error.
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[Namespace.Models.Class1]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[Namespace.Models.ParentClass]'.
I have a parent class containing the to child classes. If i use the #model IEnumerable<> directly at the child class it works, but not when pointed at the parent.
What am I doing wrong?
EDIT
Ok so these are my files.
Model1.cs
public int MyProperty1 { get; set; }
public int MyProperty2 { get; set; }
Model2.cs
public int AnotherProperty1 { get; set; }
public int AnotherProperty2 { get; set; }
ViewModel.cs
public IEnumerable<Model1> Model1 { get; set; }
public IEnumerable<Model2> Model2 { get; set; }
HomeController.cs
private ConnectContext db = new ConnectContext();
public ActionResult Index()
{
var model = from m in db.model select m;
model = db.model.OrderByDescending(m => m.ID);
return View(db.model.ToList());
}
Index.chstml
#model IEnumerable<Namespace.Models.ViewModel>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Model1.Title)
</td>
<td>
#Html.DisplayFor(modelItem => item.Model2.Title)
</td>
</tr>
}
Now with the files like this my error message is
CS1061: 'System.Collections.Generic.IEnumerable<Namespace.Models.Model1>' does not contain a definition for 'Cover' and no extension method 'Cover' accepting a first argument of type 'System.Collections.Generic.IEnumerable<Namespace.Models.Model1>' could be found (are you missing a using directive or an assembly reference?)
If you have two and only two classes you want to pass in, have you considered using a tuple?
For example:
On the controller end,
var model = new Tuple<ModelType1, ModelType2>(yourModel1, yourModel2);
return View(model);
On the view end, you'll want this at the top, along with any using statements you may need:
#model Tuple<ModelType1, ModelType2>
To access each part in the view, #Model.Item1 will be your ModelType1 and #Model.Item2 will be your ModelType2.
If you wind up with more than two classes, it might be a good idea for you to make a ViewModel class with properties for the various types you want to include. (You can also cop out and add properties to the ViewBag.)
What about just making a model class with properties that makes up the two classes you need for your view?
E.g.
public class FirstModel
{
public int Id { get; set; }
public string SomeProperty { get; set; }
}
public class SecondModel
{
public int Id { get; set; }
public string SomeOtherProperty { get; set; }
}
public class ViewModel
{
public FirstModel MyFirstModel { get; set; }
public SecondModel MySecondModel { get; set; }
}
Then in your view you use a model of ViewModel.
Try this:
public class FirstModel
{
public int Id { get; set; }
public string SomeProperty { get; set; }
}
public class SecondModel
{
public int Id { get; set; }
public string SomeOtherProperty { get; set; }
}
public class ViewModel
{
public FirstModel MyFirstModel { get; set; }
public SecondModel MySecondModel { get; set; }
}
In your Controller:
private ConnectContext db = new ConnectContext();
public ActionResult Index()
{
FirstModel firstModel = //Set FirstModel Value;
SecondModel secondModel = //Set SecondModel Value;
ViewModel viewModel = new ViewModel(){
FirstModel = firstModel,
SecondModel = secondModel
}
return View(viewModel);
}
Finally I got this working. I had to change my ViewModel, Controller and View.
ViewModel.cs (From IEnumerable to List)
public List<Model1> Model1 { get; set; }
public List<Model2> Model2 { get; set; }
HomeController.cs
private ConnectContext db = new ConnectContext();
public ActionResult Index()
{
ViewModel vm = new ViewModel();
vm.Model1 = (from m in db.Model1 select m).OrderByDescending(x => x.ID).Take(3).ToList();
vm.Model2 = (from t in db.Model2 select t).OrderByDescending(x => x.ID).Take(3).ToList();
return View(vm);
}
Index.cshtml
(So here I removed the IEnumerable and then each Foreach connects to each Model)
#model Namespace.Models.ViewModel
#foreach (var item in Model.Model1) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
</tr>
}
#foreach (var item in Model.Model2) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
</tr>
}
I am following this MVC tutorial and trying to create a database using DbContext and related model classes. The project name is "odeToFood".
Model classes:
namespace odeToFood.Models
{
public class Restaurant
{
public int Id { get; set; }
public string Name { get; set; }
public string City { get; set; }
public string Country { get; set; }
public ICollection<RestaurantReview> Reviews { get; set; }
}
public class RestaurantReview
{
public int Id { get; set; }
public string Body { get; set; }
public int Rating { get; set; }
public int RestaurantId { get; set; }
}
public class odeToFoodDb :DbContext
{
public DbSet<Restaurant> Restaurants { get; set; }
public DbSet<RestaurantReview> Reviews { get; set; }
}
}
HomeController:
public class HomeController : Controller
{
odeToFoodDb _db = new odeToFoodDb();
public ActionResult Index()
{
var model= _db.Restaurants.ToList();
return View(model);
}
}
Index View
#model IEnumerable<odeToFood.Models.Restaurant>
#{
ViewBag.Title = "Home Page";
}
#foreach (var item in Model)
{
<div>
<h4>#item.Name;</h4>
Restaurant is in : #item.City #item.Country
<hr />
</div>
}
When I run this code, according to this tutorial it should create a database and the values should be fetched (when I enter in table) but in server explorer I cannot find a database.
Neither the Index View gives an error nor can I find a database in server explorer. I tried (Localdb)\v11.0 by going to "add connection" but still it does not show any database.
I would be grateful to know what's wrong.