Question How to Foreach Through ViewModels?

Mitchelln11

Active member
Joined
Apr 10, 2020
Messages
39
Programming Experience
Beginner
How do you use a ForEach loop on ViewModels on .NET MVC?

I have 2 models:

A Park Model:
C#:
public class Park
    {
        [Key]
        public int ParkId { get; set; }
        public string ParkName { get; set; }
        public string ParkState { get; set; }
        public string ParkLatitude { get; set; }
        public string ParkLongitude { get; set; }
    }

And A HikingTrail Model:
C#:
public class HikingTrail
    {
        [Key]
        public int TrailId { get; set; }
        public string TrailName { get; set; }
        public string TrailDifficulty { get; set; }
        public string TrailSummary { get; set; }
        public double TrailLength { get; set; }
}

I wanted to use a ViewModel to access data from both of those 2 models. No matter which way I set up the ViewModel, I get errors.
C#:
    public class ParkTrailViewModel
    {
        [Key]
        public int ParkTrailId { get; set; }

        [ForeignKey("Park")]
        public int ParkId { get; set; }
        public Park Park { get; set; }

        [ForeignKey("HikingTrail")]
        public int TrailId { get; set; }
        public HikingTrail HikingTrail { get; set; }
    }

This code gives me the following error:
The model item passed into the ViewDataDictionary is of type 'walkinthepark.Models.Park', but this ViewDataDictionary instance requires a model item of type 'walkinthepark.Models.ParkTrailViewModel'.

I just want to loop through each HikingTrail on the Details view, which uses the ParkTrailViewModel
C#:
@foreach (var item in Model.HikingTrail)
        {

        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.TrailName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.TrailDifficulty)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.TrailLength)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.TrailCondition)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.TrailSummary)
            </td>
        </tr>
        }

I've seen this error before as well, I just can't remember how I got it.
CS1579 C# foreach statement cannot operate on variables of type because does not contain a public instance definition for 'GetEnumerator'
 
You don't loop through a single object. That doesn't make sense. You loop through a list of objects, so the thing you loop through has to be a list of some sort. You say that you want to "loop through each HikingTrail" but there's only one HikingTrail. Look at your code; that's what it says:
C#:
public HikingTrail HikingTrail { get; set; }
That's like saying "I have an egg in my hand and I want to crack each egg in the carton".

I suspect that your design is just wrong, all the way back to the database. It looks like you have a Park table with ParkId as primary key, a HikingTrail table with HikingTrailId as primary key and a ParkTrail table with ParkTrailId as primary key and ParkId and HikingTrailId as foreign keys. That's wrong. That would mean that you have a many-to-many relationship between parks and hiking trails. That would mean that a park could contain many hiking trails and a hiking trail could be in many parks. Unless your trails are very long and cross multiple parks, that doesn't make sense. I would think that it should be a one-to-many relationship, in which case you would get rid of the ParkTrail table and add ParkId to the HikingTrail table as a foreign key.

In that case, your view model would have no ParkTrailId and ParkId would be the primary key. Instead of this:
C#:
[ForeignKey("HikingTrail")]
public int TrailId { get; set; }
public HikingTrail HikingTrail { get; set; }
you'd have something like this:
C#:
public IEnumerable<HikingTrail> HikingTrails { get; set; }
Now you've actually got as list of multiple HikingTrail objects to loop through.
 
You're right, I was just wrong.
I ended up adding something to my ParkController's Details Task<ActionResult> and it worked. I didn't even use the ViewModel.
park.HikingTrail = _context.HikingTrails.Where(i => i.ParkId == id).ToList();

What you're saying reminds to sit back and look at basic principles. I was at the point of not getting anything to work and trying everything. That's when all principle goes out the window.

I didn't try your public IEnumerable<HikingTrail> HikingTrails { get; set; }, but I think I will give that a shot on another part of this project.
Thank you.
 
Note that any member name should indicate what it represents. If you're member is intended to store multiple items in a list then it should not have a singular name notice here:
C#:
park.HikingTrail = _context.HikingTrails.Where(i => i.ParkId == id).ToList();
that the property on the right is a plural for that very reason, while yours is incorrectly singular.
 
Note that any member name should indicate what it represents. If you're member is intended to store multiple items in a list then it should not have a singular name notice here:
C#:
park.HikingTrail = _context.HikingTrails.Where(i => i.ParkId == id).ToList();
that the property on the right is a plural for that very reason, while yours is incorrectly singular.



So should it be?
C#:
parks.HikingTrails = _context.HikingTrails.Where(i => i.ParkId  == id).ToList();
 
Back
Top Bottom