Complex ViewModel - View cannot Automap values from model Advice Needed.. - c#

I have a complex View. It has data from 4 Models. The models are all static and work as expected. I have created a ViewModel to attempt to show just the data needed for this view. It is made up of Competitors and some complex Classes and Events they participate in.
I have made a complex ViewModel. When I walk through the Controller, I can see all three parts being constructed from the ViewModel. Its all there including data. When I try to map the values using Intellesense in the View, it has no way of knowing this data, or has no mapping from the complex ViewModel. Am I doing this right? I have tried several ways to map these values to the View. I think I need to initialize or map the values to the Models derived from, I just cannot figure out how.
Please advise on how to map these values, data elements to the view.
ViewModel:
Compeditor is an from an actual model direct to the DB
The rest of the data is gathered from multiple tables and passed to view from controller
namespace eManager.Web2.Models
{
public class CompDetailPlus
{
public CompDetailPlus()
{
this.Compeditor = new Compeditor();
}
public virtual Compeditor Compeditor { get; set; }
public virtual IEnumerable<InEventClass> InEventClass { get; set; }
public virtual IEnumerable<AllEventClasses> AllEventClasses { get; set; }
}
public class Compeditor
{
[Key]
public virtual int CompeditorId { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual string MiddleInt { get; set; }
public virtual string StreetAddress { get; set; }
public virtual string City { get; set; }
public virtual string State { get; set; }
public virtual string PostalCode { get; set; }
public virtual string EmailAddress { get; set; }
public virtual string HomePhone { get; set; }
public virtual string CellPhone { get; set; }
public virtual double Height { get; set; }
public virtual double Weight { get; set; }
public virtual int Age { get; set; }
public virtual int Event_CompId { get; set; }
}
public class InEventClass
{
public virtual int EventClassID { get; set; }
public virtual string ClassName { get; set; }
public virtual bool IsSelected { get; set; }
}
//duplicate to simplify how the second list is pulled and then combined with first list
public class AllEventClasses
{
public virtual int EventClassID { get; set; }
public virtual string ClassName { get; set; }
public virtual bool IsSelected { get; set; }
}
}
Controller:
public ActionResult CompeditorDetail(int CompeditorId)
{
//Pull the Competitor detail for the ID passed in
var comp = _db.Compeditors.Single(c => c.CompeditorId == CompeditorId);
//Pull a list of Event-Classes the competitor is already signed up for on current event
var nlist = (from o in _db.Compeditors
join o2 in _db.Event_Class_Compeditors_s on o.CompeditorId equals CompeditorId
where o.CompeditorId.Equals(CompeditorId)
join o3 in _db.Event_Classes on o2.EventClassID equals o3.EventClassID
where o2.EventClassID.Equals(o3.EventClassID)
join o4 in _db.Class_Definitions on o3.ClassID equals o4.Class_Definition_ID
where o3.ClassID.Equals(o4.Class_Definition_ID)
select new InEventClass()
{
ClassName = o4.Class_Name,
EventClassID = o2.EventClassID,
IsSelected = true
}).ToList();
//pull a complete list of Event Classes that are avaiaible
var totallist = (from o in _db.Event_Classes
join o2 in _db.Event_Classes on o.ClassID equals o2.ClassID
where o.ClassID.Equals(o2.ClassID)
join o3 in _db.Class_Definitions on o2.ClassID equals o3.Class_Definition_ID
where o2.ClassID.Equals(o3.Class_Definition_ID)
join o4 in _db.Events on o.EventID equals o4.EventID
where o.EventID.Equals(o4.EventID)
where o4.CurrentEvent.Equals(true)
select new AllEventClasses()
{
ClassName = o3.Class_Name,
EventClassID = o2.EventClassID,
IsSelected = false
}).ToList();
var whatsleft = totallist.Where(eachtotalclass => !(nlist.Any(eachClassIHave => eachClassIHave.EventClassID == eachtotalclass.EventClassID))).ToList();
var model = new CompDetailPlus { AllEventClasses = whatsleft, Compeditor = comp, InEventClass = nlist };
return View(model);
}
View:
(Has to show the Competitor detail and a compound list of Event_Classes they are in)
In the view, I cannot see the values for any data.. all error on run and no good for display.
#model IEnumerable<eManager.Web2.Models.CompDetailPlus>
#{
ViewBag.Title = "Competitor's Detail";
}
<h2>#ViewBag.Title</h2>
<fieldset>
<legend>Compeditor</legend>
<table border="1" >
<tr>
<td>
<div class="display-field">
#Html.HiddenFor(model => model.Compeditor.CompeditorId)
</div>
<b>First Name</b>
<div class="display-field">
#Html.DisplayFor(model => model.Compeditor.FirstName)
</div>
</td>
<td>
<b>Last Name</b>
<div class="display-field">
#Html.DisplayFor(model => model.Compeditor.LastName)
</div>
</td>
#using (Html.BeginForm("CompeditorDetail", "Compeditor", FormMethod.Post))
{
foreach (var item in Model)
{
<input type="checkbox" name="MyID" value="#item.AllEventClasses.IsSelected"/> #item.InEventClass.ClassName <br />
<input type="hidden" name="CompeditorID" value="#item.InEventClass.CompeditorId" />
}
}
</td>

Your View accepts a model of IEnumerable eManager.Web2.Models.CompDetailPlus which would be fine, but your controller is sending a single eManager.Web2.Models.CompDetailPlus object.
Try changing this in your View
#model IEnumerable<eManager.Web2.Models.CompDetailPlus>
to this:
#model eManager.Web2.Models.CompDetailPlus
And change the bottom part of your view so that it's iterating through Enumerable compaosite items inside your model.

Related

Display table with category name in one column and list of items belonging to category in second column with links on Details View in ASP.NET MVC View

I my ASP.NET MVC Core 3.1 app I have Model that stores professions which looks like this:
public partial class Professions
{
public int ProfessionID { get; set; }
public int? ProfessionGroupID { get; set; }
public string ProfessionTitle { get; set; }
public string ProfessionDescription { get; set; }
}
So each profession belongs to some group of professions, therefore Model for profession groups looks like this:
public partial class ProfessionGroups
{
public ProfessionGroups()
{
Professions = new HashSet<Professions>();
}
public int ProfessionGroupID { get; set; }
public int ProfessionGroupTitle { get; set; }
public string ProfessionGroupDescription { get; set; }
public virtual ICollection<Professions> Professions { get; set; }
}
How can I display list of groups of professions in one columns and list of professions in another column
with links which leads to each profession Details View?
This is how output table in some View should look:
ProfessionGroups
Professions
Physiotherapy
Graduated physiotherapist Physiotherapist (bachelor degree) Physiotherapy technician
Geology
Geological technician Geology engineer
So far I've created ViewModel that suppose to hold needed data:
public class ProfGroupsVM
{
public int ProfessionGroupID { get; set; }
public string ProfessionGroupTitle { get; set; }
public List<int> ProfIDs { get; set; } = new List<int>();
public List<string> ProfTitles { get; set; } = new List<string>();
}
For each ProfessionGroupID it has to populate ProfIDs with list of professions belonging to that group and ProfTitles should hold professions titles.
So in Controller so far I have:
var profGroupsVM= new ProfGroupsVM();
var result = from p in _context.Professions
group p.ProfessionID by p.ProfessionGroupID into g
select new { ProfessionGroupID = g.Key, ProfessionIDs= g.ToList() };
I don't know how to assign this result back to my ViewModel nor how to display desired View.
It's better to change the ProfGroupsVM model to this:
public class ProfGroupsVM
{
public int ProfessionGroupID { get; set; }
public string ProfessionGroupTitle { get; set; }
public List<ProfInfo> Professions { get; set; }
public class ProfInfo
{
public int Id { get; set; }
public string Title { get; set; }
}
}
And to get information use this:
_dbContext.ProfessionGroups.Include(x => x.Professions)
.Select(x => new ProfGroupsVM()
{
ProfessionGroupID = x.ProfessionGroupID,
ProfessionGroupTitle = x.ProfessionGroupTitle,
Professions = x.Professions.Select(p => new ProfGroupsVM.ProfInfo
{
Id = p.ProfessionID,
Title = p.ProfessionTitle
}).ToList()
}).ToList();
And in you view try this to show information(I'm not good in UI :)):
#model List<ProfGroupsVM>
<div>
<ul>
#foreach (var group in Model)
{
<li>#group.ProfessionGroupTitle</li>
<ul>
#foreach (var profession in group.Professions)
{
<li>#profession.Title</li>
}
</ul>
}
</ul>
Or if you stick with your ViewModel for ul part you can put this:
<ul>
#foreach (var idsTitles in item.ProfIDs.Zip(#item.ProfTitles, Tuple.Create))
{
<li><a asp-action="Details" asp-controller="Profession" asp-route-id="#idsTitles.Item1">#idsTitles.Item2</a></li>
}
</ul>

CRUD operations for multiple related records in different tables from single view in MVC C#

I was hoping I could get some assistance on this functionality I am trying to achieve. I have searched, but i do not seem to be able to translate the examples/tutorials I have found to make it work in my own code.
For brevity, let's say I have 2 Models with a one to many relationship between the two. Let's say it is parents and children. One parent can have zero or many children. Each child can only have 1 parent:
namespace MyApp.Models
{
public partial class Parent
{
[Key]
public int parent_id { get; set; }
public string parent_name { get; set; }
public string parent_address { get; set; }
public ICollection<Child> Child { get; set; }
}
public partial class Child { get; set; }
{
[Key]
public int child_id { get; set; }
public int parent_id { get; set; }
public string child_name { get; set; }
public string child_allergies { get; set; }
public virtual Parent parent { get; set; }
}
}
Entity created the tables in the database properly, assigning primary/foreign keys where they needed to be.
I put the common fields in a viewmodel to render them in my view:
using MyApp.Models;
namespace MyApp.ViewModels
{
public class ParentChildViewModel
{
public int parent_id { get; set; }
public string parent_name { get; set; }
public string parent_address { get; set; }
public string child_name { get; set; }
public string child_allergies { get; set; }
}
}
I have my view written as below:
#model MyApp.ViewModels.ParentChildViewModel
#using (Html.BeginForm())
{
<div>
#Html.LabelFor(model => model.parent_name)
#Html.EditorFor(model => model.parent_name)
</div>
<div>
#Html.LabelFor(model => model.parent_address)
#Html.EditorFor(model => model.parent_address)
</div>
<table id="child_table">
#{ Html.RenderPartial("_children"); }
</table>
<div>
<button id="add">Add Child</button>
<button id="rem">Remove Child</button>
</div>
<div>
<input type="submit" value="Create" />
</div>
}
<script type="text/javascript">
$("#add").click(function () {
$.ajax({
url: "#Url.Action("BlankChRow")",
cache: false,
success: function (html) {
$("#child_table").append(html);
}
});
return false;
});
$("#rem").click(function () {
$("#child_table tbody tr:last")
.remove();
return false;
});
</script>
I created a partial view for the child so I can repeat those:
#model MyApp.ViewModels.ParentChildViewModel
#using (Html.BeginCollectionItem("children"))
{
<tr>
<td>
<div>
#Html.LabelFor(model => model.child_name)
#Html.EditorFor(model => model.child_name)
</div>
</td>
<td>
<div>
#Html.LabelFor(model => model.child_allergies)
#Html.EditorFor(model => model.child_allergies)
</div>
</td>
</tr>
}
Then, in my controller (this is where I am stuck):
private ApplicationDbContext db = new ApplicationDbContext();
public ActionResult BlankChRow()
{
return PartialView("_children");
}
public ActionResult Create()
{
return View(new ParentChildViewModel());
}
[HttpPost]
public ActionResult Create(ParentChildViewModel pcvm)
{
var parent = new Parent()
{
parent_id = pcvm.parent_id,
parent_name = pcvm.parent_name,
parent_address = pcvm.parent_address
};
var child = new Child()
{
parent_id = pcvm.parent_id,
child_name = pcvm.child_name,
child_allergies = pcvm.child_allergies
};
if (ModelState.IsValid)
{
db.Parent.Add(parent);
db.Child.Add(child);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(pcvm);
}
I have experimented a few different ways of doing this... but I am unable to get this working the way I would like. Ideally, the View can be brought up, and while they enter the Parent's data, they could add one or many children. The children that are added would each be their own record in the Child table/entity while having the appropriate parent_id.
Any help is appreciated.
I see that you want to generate a list of children for a given parent but your viewmodel doesn't look so.
using MyApp.Models;
namespace MyApp.ViewModels
{
public class ParentChildViewModel
{
public int parent_id { get; set; }
public string parent_name { get; set; }
public string parent_address { get; set; }
public string child_name { get; set; }
public string child_allergies { get; set; }
}
}
Try a viewmodel with a list of children.
Something like this :
using MyApp.Models;
namespace MyApp.ViewModels
{
public class ParentChildViewModel
{
public int parent_id { get; set; }
public string parent_name { get; set; }
public string parent_address { get; set; }
public IEnumerable<Child> children { get; set; }
}
}
I'm supposing here that you just want to iterate over the list. That's why I use the IEnumerable interface instead of the IList interface.
To add a child in the list, you could call the "Create" function of your controller and pass the parent_id of the new child.
In your controller you can therefore create a new child for a given parent in the database using your application context.
Once the database transaction done, you can create a new ParentChildViewModel and fulfill it with the corresponding children and return it to the view.

ASP.NET MVC Many-to-many relationship with viewmodel

I'm trying to display a list of books that will show the details for each book. It all works properly, except for the properties which have many-to-many relationships with the Books model.
Here is my Book model (I removed annotations for readability):
public class Book
{
public int BookId { get; set; }
public string title { get; set; }
public Int32 isbn { get; set; }
public string author { get; set; }
public string summary { get; set; }
public string series { get; set; }
public string amazonLink { get; set; }
public string pubLink { get; set; }
public int? GradeLevelId { get; set; } //Foreign Key for GradeLevel
public bool needsEdit { get; set; }
public int? LexileLevelId { get; set; } //Foreign Key for LexileLevel
public DateTime dateAdded { get; set; }
public Book()
{
dateAdded = DateTime.Now;
}
public string comments { get; set; }
public virtual GradeLevel GradeLevel { get; set; }
public virtual LexileLevel LexileLevel { get; set; }
//Navigation Properties
public virtual ICollection<Recommendation> Recommendations { get; set; }
public virtual ICollection<RelevantGenre> RelevantGenres { get; set; }
}
The two navigation properties (Recommendation and RelevantGenre) are for the associative/joining tables, and that's where I'm having issues. To keep things simple, I'm going to focus on the RelevantGenre model. Each book can have more than one Genre, so the RelevantGenre is the join table between Book and Genre.
Here's the Model for those:
public class RelevantGenre
{
//Both are primary keys
[Key]
[Column(Order = 1)]
public int BookId { get; set; } //Foreign Key to Book
[Key]
[Column(Order = 2)]
public int genreId { get; set; } //Foreign Key to Genre
public virtual Book Book { get; set; } //Nav property
public virtual Genre Genre { get; set; } //Nav property
}
public class Genre
{
public int GenreId { get; set; }
public string genreTitle { get; set; }
public int genreOrder { get; set; }
//Navigation Property to RelevantGenre
public ICollection<RelevantGenre> RelevantGenres { get; set; }
}
Here's the Controller:
// GET: Books
public ActionResult Index(string filter, string searchString)
{
var viewModel = new BookListViewModel();
if (String.IsNullOrEmpty(searchString) && String.IsNullOrEmpty(filter))
{
var results = from b in db.Books select b;
var resultsList = (results.ToList());
viewModel.Books = resultsList;
return View(viewModel);
}
else
{
var results = from b in db.Books select b;
//Filtering the book list
switch (filter)
{
case "HR":
results = from b in db.Books
join r in db.Recommendations
on new { b.BookId } equals
new { r.BookId }
where (r.RecommendationTypeId == 1)
select b;
break;
default:
results = from b in db.Books select b;
break;
}
if(!String.IsNullOrEmpty(searchString))
{
//Search query results
var searchResults = from b in db.Books
.Where(model => model.title.Contains(searchString) || model.author.Contains(searchString)
|| model.series.Contains(searchString))
select b;
if (searchResults != null )
{
results = searchResults;
}
else
{
ViewBag.SpanText = "Sorry, no results founds. Please try your search again.";
}
}
var resultsList = (results.ToList());
viewModel.Books = resultsList;
return View(viewModel);
}
}
As you can see, it's returning a viewModel, because I thought that made the most sense for how to return a combination of model data.
Here's the viewmodel:
public class BookListViewModel
{
public List<Book> Books { get; set; }
public int BookId { get; set; }
public string title { get; set; }
public string author { get; set; }
public Int32 isbn { get; set; }
public string series { get; set; }
public int? GradeLevelId { get; set; }
public string gradeLevelName { get; set; }
public int? LexileLevelId { get; set; }
public string lexileLevelName { get; set; }
public Recommendation Recommendation { get; set; }
public int RecommendationTypeId { get; set; }
public string recName { get; set; }
public RelevantGenre RelevantGenre { get; set; }
public int genreId { get; set; }
}
And lastly, here's the view:
#model FavBooks.ViewModels.BookListViewModel
#{
ViewBag.Title = "All Books";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Books</h2>
<p class="details">
#Html.ActionLink("Browse All Books in List Format", "FullList", "Books")
</p>
#foreach (var item in Model.Books)
{
<div class="row fullBorder">
<div class="col-md-2 col-sm-2">
<img src="~/Content/Images/harrypotterbook.png" class="bookThumb" alt="Book Image" />
</div>
<div class="col-md-3 col-xs-3">
<h3>
<a href="#Url.Action("Details", "Books", new { id = item.BookId })" class="darkLink bookTitle">
#Html.DisplayFor(modelItem => item.title)
</a>
</h3>
<h4>By #Html.DisplayFor(modelItem => item.author)</h4>
<p><strong>ISBN:</strong> #Html.DisplayFor(modelItem => item.isbn)</p>
</div>
<div class="col-md-3 col-sm-4 bookMargins">
#{
if (item.series != null)
{
<p><strong>Series:</strong> #Html.DisplayFor(modelItem => item.series) </p>
}
else
{
<p></p>
}
}
<p><strong>Grade Level:</strong> #Html.DisplayFor(modelItem => item.GradeLevel.gradeLevelName )</p>
<p><strong>Lexile Level:</strong> #Html.DisplayFor(modelItem => item.LexileLevel.lexileLevelName)</p>
</div>
<div class="col-md-4 col-sm-3">
#Html.ActionLink("View Book Details", "Details", "Books", new { id = item.BookId }, new { #class="btn btn-default btnBookDetails" })
</div>
</div>
}
You can see that my view displays a list of items from Model.Books using a foreach loop. For each book, I'd like it to also display the RelevantGenres that are connected to the book, but it's not letting me. The GradeLevel and LexileLevel properties connect just fine (those are one-to-many), but it doesn't seem to register any of the many-to-many relationships which are not directly part of the Book model.
I feel like I'm missing something basic here, or maybe there's an issue with my view-model setup. Do you see where I went wrong on this or what I can do to display each book's genres?
EDIT:
Let me get more specific with what I tried.
I saw here that it's possible to use a foreach inside of another foreach to display a loop. But when I try that, it tells me that the "foreach cannot operate on that... because Favbooks.Models.Book does not contain a public definition for GetEnumerator". So I tried changing the #model to an IEnumerable<> and looping through the whole Model (instead of foreach(var item in Model.Books) but then it still wouldn't work. In that situation, it gave me an error saying:
'BookListViewModel' does not contain a definition for 'RelevantGenres' and no extension method 'RelevantGenres' accepting a first argument of type 'BookListViewModel' could be found (are you missing a using directive or an assembly reference?)
Because that wasn't working, I kept the #model with #model FavBooks.ViewModels.BookListViewModel like it was initially, and and tried putting in #Html.DisplayFor(modelItem => item.Genres.genreTitle) but it doesn't recognize Genre or RelevantGenre.
To sum up, the issue is that if I loop through Model.Books, then it won't recognize anything in the viewmodel other than the Books list. But if I loop through the overall Model, then it still won't recognize the RelevantGenres, and now it started giving me another error like this:
The model item passed into the dictionary is of type 'FavBooks.ViewModels.BookListViewModel', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[FavBooks.ViewModels.BookListViewModel]'.
I'm sorry if this isn't totally clear. I haven't worked so much with viewmodels before and I see that I must have set it up wrong, but I just don't know how to get this working...
Have you tried .Include()? This will populate all the related data in the navigation property. Refer https://learn.microsoft.com/en-us/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/reading-related-data-with-the-entity-framework-in-an-asp-net-mvc-application for more detials.
eg:
var BookList = _context.Book.Where(m=>m.BookId==id).Include(m=>m.Recommendations).Include(m=>m.RelevantGenres)
This will query a record of Book whose BookId=id and will populate all the related navigation properties.
There's also .ThenInclude()
A property of public List<Book> Books { get; set; } should be enough as this will store all the data related to your retrieved entity.
and below is example of how you can access the fields of a navigation property.
#model BookListViewModel
foreach(var b in Model.Books)
{
#HtmlDisplayFor(modelItem=>b.title)
foreach(var r in b.RelevantGenres)
{
#HtmlDisplayFor(modelItem=>r.GenereName)
}
}
Myself being fairly new to .netcore mvc, I don't know much either. But I hope this helps to point you in the right direction if not completely solve your issue.

Displaying data from multiple models on one view (images and text)

Hi everyone so I am trying to create an application using asp.net mvc with a code first database that allows the users to be able to create a blog post with as many images as they wish.I have the data stored in the database but I I am currently trying to have the the head, body and images displaying in the display view this is what I would like it to look like : http://imgur.com/a/IR19r but I am not sure how to accomplish this. I am able to display the head and body but cannot get the images from the image table here is the database diagram: http://imgur.com/a/lvwti
Currently this is the error I get when i add this to the view #Html.DisplayFor(modelItem => item.Images)
An exception of type 'System.Data.Entity.Core.EntityCommandExecutionException' occurred in EntityFramework.SqlServer.dll but was not handled in user code
Additional information: An error occurred while executing the command definition. See the inner exception for details.
Model
public partial class PostModel
{
public PostModel()
{
Images = new List<ImageModel>();
}
[Key]
[HiddenInput(DisplayValue = false)]
public int ID { get; set; }
[Required(ErrorMessage = "Heading is Required")]
[Display(Name = "Heading")]
public string Heading { get; set; }
[Required(ErrorMessage = "Body is Required")]
[DataType(DataType.MultilineText)]
[Display(Name = "Body")]
public string Body { get; set; }
public virtual ICollection<ImageModel> Images { get; set; }
public IEnumerable<HttpPostedFileBase> File { get; set; }
}
public class ImageModel
{
[Key]
public int ID { get; set; }
public string Path { get; set; }
public virtual PostModel Post { get; set; }
public string DisplayName { get; set; }
}
public class ImageVM
{
public int? ID { get; set; }
public string Path { get; set; }
public string DisplayName { get; set; }
public bool IsDeleted { get; set; }
}
public partial class PostVM
{
public PostVM()
{
Images = new List<ImageVM>();
}
public int? ID { get; set; }
public string Heading { get; set; }
public string Body { get; set; }
public IEnumerable<HttpPostedFileBase> Files { get; set; }
public List<ImageVM> Images { get; set; }
}
DbContext
public class EFDbContext : DbContext
{
public DbSet<PostModel> Posts { get; set; }
public DbSet<PostVM> PostVMs { get; set; }
public DbSet<ImageModel> Images { get; set; }
public DbSet<ImageVM> ImageVMs { get; set; }
}
Controller
public ViewResult Display()
{
return View(repository.Posts)
}
View
#model IEnumerable<Crud.Models.PostModel>
#{
ViewBag.Title = "Index";
}
#foreach (var item in Model)
{
<div>
#Html.DisplayFor(modelItem => item.Heading)
</div>
<div>
#Html.DisplayFor(modelItem => item.Body)
</div>
<div>
#Html.DisplayFor(modelItem => item.Images)
#*<img class="img-thumbnail" width="150" height="150" src="/Img/#item.Images" />*#
</div>
}
Here is alternative controller I tried but am not using as I got this error when i tried let Images = i.Path and wasn't really sure if this was meant to be how it was done
Cannot implicity convert typeCrud 'string' to 'System.Collections.Generic.List Crud.Models.ImageVm '
public ViewResult Display()
{
IEnumerable<PostVM> model = null;
model = (from p in db.Posts
join i in db.Images on p.ID equals i.Post
select new PostVM
{
ID = p.ID,
Heading = p.Heading,
Body = p.Body,
Images = i.Path
});
return View(model);
}
item.Images is a collection. So loop through that and display the images.
<div>
#foreach(var image in item.Images)
{
<img src="#image.Path" />
}
</div>
You need to make changes to the src property depending on what value you store in the Path property of image.
You can correct your other action method like this
public ViewResult Display()
{
var posts = db.Posts.Select(d => new PostVM()
{
ID = d.ID ,
Heading = d.Heading,
Body = d.Body,
Images = d.Images.Select(i => new ImageVM() { Path = i.Path,
DisplayName = i.DisplayName }
).ToList()
}).ToList();
return View(posts);
}
Now since you are returning a list of PostVM, make sure your Display view is strongly typed to that.
#model List<PostVM>
<h1>Posts</h1>
#foreach(var p in Model)
{
<h3>#p.Heading</h3>
<p>#p.Body</p>
#foreach(var image in item.Images)
{
<img src="#image.Path" />
}
}
Also, there is no point in keeping the view model classes on your db context. Keep only your entity models. View models are only for the use of UI layer.
public class EFDbContext : DbContext
{
public DbSet<PostModel> Posts { get; set; }
public DbSet<ImageModel> Images { get; set; }
}

Displaying an ICollection in a View

I have a model that was auto-generated from my SQL database.
class Organization
{
public Organization()
{
this.ContactTitles = new HashSet<ContactTitle>();
this.OrganizationAddresses = new HashSet<OrganizationAddress>();
this.OrganizationBusinessTypes = new HashSet<OrganizationBusinessType>();
this.OrganizationCountries = new HashSet<OrganizationCountry>();
this.OrganizationEmails = new HashSet<OrganizationEmail>();
this.OrganizationMemberships = new HashSet<OrganizationMembership>();
this.OrganizationNotes = new HashSet<OrganizationNote>();
this.OrganizationPhones = new HashSet<OrganizationPhone>();
this.OrganizationWebsites = new HashSet<OrganizationWebsite>();
this.Contacts = new HashSet<Contact>();
this.OrganizationIndustryCodes = new HashSet<OrganizationIndustryCode>();
}
public int OrganizationID { get; set; }
public string Name { get; set; }
public virtual ICollection<ContactTitle> ContactTitles { get; set; }
public virtual ICollection<OrganizationAddress> OrganizationAddresses { get; set; }
public virtual ICollection<OrganizationBusinessType> OrganizationBusinessTypes { get; set; }
public virtual ICollection<OrganizationCountry> OrganizationCountries { get; set; }
public virtual ICollection<OrganizationEmail> OrganizationEmails { get; set; }
public virtual ICollection<OrganizationMembership> OrganizationMemberships { get; set; }
public virtual ICollection<OrganizationNote> OrganizationNotes { get; set; }
public virtual ICollection<OrganizationPhone> OrganizationPhones { get; set; }
public virtual ICollection<OrganizationWebsite> OrganizationWebsites { get; set; }
public virtual ICollection<Contact> Contacts { get; set; }
public virtual ICollection<OrganizationIndustryCode> OrganizationIndustryCodes { get; set; }
}
In my Organization View, on my Index page - it is strongly typed to my Organization Model.
I am trying to displaying the Membership information, on the Organization index page, that I believe should be in the ICollection. Unless I am miss-interpreting what that does.
When I go to put a #Html.DisplayFor(modelItem => item.OrganizationMemberships. to grab the data in the OrganizationMembership table, it does not show up on IntelliSense. I only need to be able to display the data, I don't have to submit any changes with a form.
Since the model is an enumerable type -- #model PagedList.IPagedList<VAGTC.Models.Organization> -- you'll need to iterate through them in your main view:
#foreach (var organization in Model)
{
#Html.DisplayFor(model => organization)
}
Next, create a display template for the class Organization. Under Views/Shared/DisplayTemplates add a view Organization.cshtml:
#model VAGTC.Models.Organization
Now this is the main view that renders your class. Here you can iterate over the membership items:
#foreach (var membership in Model.OrganizationMemberships)
{
#Html.DisplayFor(model => membership)
}
Now again, create a partial view for the OrganizationMembership class by adding OrganizationMembership.cshtml under Views/Shared/DisplayTemplates.

Categories