Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

c# - ASP.NET MVC Viewmodel returns nothing

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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);
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...