tommy_o
tommy_o

Reputation: 3783

ASP.NET MVC: Displaying multiple models in one view (one-to-many relationship)

I'm trying to put together (what I thought was) a simple ASP.NET web application using MVCScaffolding and ASP.NET. There is a basic hieararchy of data tables in SQL: dbo.Albums, dbo.Tracks.

The model is easy. For albums:

public class Albums {
public int ID { get; set; }
public string Artist { get; set; }
    public string AlbumTitle { get; set; }
public string Notes { get; set; } 
}

public class Tracks {
public int ID { get; set; }
public int AlbumID { get; set; }
public string TrackTitle { get; set; }
public string Notes { get; set; }
}

The basic CRUD views are built and working fine. However, I'm trying to build a view that displays the Album model data followed by a table with one row for each track record for a given AlbumId. Essentially, this is the Details view followed by the Index view from the MVCScaffolding template, but it uses two Models and has one parameter (the ID from Albums table).

I tried to add the models together to access the data from there, but I can't figure out how to iterate over a list (the index view uses @model IEnumerable<Music.Models.Tracks>). This is the combined model:

public class AlbumsExtended
{
    public Albums Albums { get; set; }
    public Tracks Tracks { get; set; }
}

And I am trying to access it in AlbumsExt.cshtml with @model Music.Models.AlbumsExtended. The controller looks like this:

public ViewResult AlbumExt(int id)
    {
        return View(tracksRepository.All.Where(tracks => tracks.AlbumId == id));
    }

But obviously that isn't correct.

Upvotes: 3

Views: 6500

Answers (1)

Joel Etherton
Joel Etherton

Reputation: 37533

Given your structure of Albums and Tracks, it would probably be preferable to have a direct 1 to many relationship between Albums and Tracks so that 1 album can have many tracks. Regardless of how many albums a track may appear on, your models could look like:

public class Albums {
    public int ID { get; set; }
    public string Artist { get; set; }
    public string AlbumTitle { get; set; }
    public string Notes { get; set; } 
    public IQueryable<Track> Tracks { get; set; }
}

public class Track {
    public int ID { get; set; }
    public int AlbumID { get; set; }    // This may be unnecessary 
    public string TrackTitle { get; set; }
    public string Notes { get; set; }
}

This would allow your data layer to populate all of the tracks that belong to a specific Album, but if you don't need to know the tracks it can just remain null. But your data layer just needs to fetch the album and then populate the Tracks property with an IQueryable object.

public ViewResult AlbumExt(int id)
{
    Album album = albumRepository.All.Where(a => a.ID == id);
    album.Tracks = tracksRepository.All.Where(t => t.AlbumId == id);
    return View(album);
}

This would give you a single model, but all of the related tracks would still be accessible through the Model.Tracks property in the view:

@model MyNameSpace.Album

@{
    foreach (var track in Model.Tracks)
    {
        <text>
            <h1>@track.TrackTitle</h1><br />
        </text>
    }    
}

Upvotes: 5

Related Questions