user793468
user793468

Reputation: 4966

display data form multiple tables in a strongly typed view

I have a strongly typed view which displays students from a database table "Student_A"

View:

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<IEnumerable<Student.Models.Student_A>>" %>
    <table>
    <% foreach (var item in Model) { %>

        <tr>
            <td>
                <%= Html.Encode(item.StudentName) %>
            </td>
            <td>
                <%= Html.Encode(item.StudentId) %>
            </td>
        </tr>

    <% } %>

    </table>

Controller:

    public ActionResult ShowStudents()
    {
        ViewData.Model = stud.Student_A.Where(a => a.StudentId != 0);
        return View();
    }

I have another table "Student_B" which stores students as well, I would like to display this students in my view as well. Something like:

    public ActionResult ShowAllStudents()
    {
        var StudentA = stud.Student_A.Where(a => a.StudentId != 0);
        var StudentB = stud.Student_B.Where(a => a.StudentId != 0);
        ViewData.Model = StudentA + StudentB;

        return View();
    }

Is it possible to show data from two different tables in a strongly typed view in a single controller action? Or will I have to create a database view that displays students from "Student_A" and "Student_B" tables and then display them in a view?

Any help is much appreciated

Upvotes: 3

Views: 989

Answers (3)

Nick Albrecht
Nick Albrecht

Reputation: 16928

I had to do something similar for a Treeview instead of a table and needed to combine two different collections in order to generate a treeview from a single collection. In my case I was able to combine them using this...

var allStudents = StudentA.Union((IEnumerable<Object>)StudentB);

Then in your code when you iterate through each object in the collection you can test the datatype of the object and display it how you want, in case you want to use different code to render different types of students. I needed to do this because in my case a node that had child items was a completely different type than the node without child items.

Note that by using Object as your root collection type instead of some sort of shared inheritance (an interface for example) you'll have no way to sort your combined collection or filter them.

If you need to mix the two collections rather than just appending one to the end of the other, you'll have to use some sort of shared inheritance.

UPDATE:

Sample code to show that this works. I tested in LinqPad, but I'm sure it'd work just as well in Visual Studio.

public class Student_A
{
    public int Id{get;set;}
    public string FirstName{get;set;}
    public string LastName{get;set;}
}

public class Student_B
{
    public int Id{get;set;}
    public string FirstName{get;set;}
    public string MiddleName{get;set;}
    public string LastName{get;set;}
}

void Main()
{
    List<Student_A> StudentAs = new List<Student_A>();
    StudentAs.Add(new Student_A(){Id = 1, FirstName = "Jack", LastName = "Smith"});
    StudentAs.Add(new Student_A(){Id = 3, FirstName = "Sarah", LastName = "Jane"});
    StudentAs.Add(new Student_A(){Id = 7, FirstName = "Zack", LastName = "Hall"});

    List<Student_B> StudentBs = new List<Student_B>();
    StudentBs.Add(new Student_B(){Id = 2, FirstName = "Jane", MiddleName = "T.", LastName = "Kelly"});
    StudentBs.Add(new Student_B(){Id = 9, FirstName = "Rose", MiddleName = "Marie", LastName = "Tyler"});
    StudentBs.Add(new Student_B(){Id = 4, FirstName = "Bobby", MiddleName = "Stephen", LastName = "Singer"});

    var result = StudentAs.Union((IEnumerable<Object>)StudentBs);

    result.Dump();
}

Upvotes: 0

dove
dove

Reputation: 20674

You can create a view model with both

public class StudentsViewModel
{
  public List<Student.Models.Student_A> StudentsA {get;set}
  public List<Student.Models.Student_B> StudentsA {get;set}
}

and return this in your view, if indeed the A and B students have different fields

var viewModel = new StudentsViewModel();
viewModel.StudentsA = stud.Student_A.Where(a => a.StudentId != 0);
viewModel.StudentsB = stud.Student_B.Where(a => a.StudentId != 0);
return View(viewModel);

Upvotes: 1

Eli Gassert
Eli Gassert

Reputation: 9763

you need to store the resutls in an "agnostic" way. For example

public class StudentInfo
{
public string Type { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
...
}


var students = stud.Student_A.Where(...).Select(a => new StudentInfo { Type = "Student_A", FirstName = a.FirstName, LastName = a.LastName });

students.concat( stud.Student_B.Where(...).Select(b => new StudentInfo { Type = "Student_B", FirstName = b.FirstName, LastName = b.LastName });

ViewData.Model = students;

return View();

By doing this, you have a common class of student info to store common properties which can be used as a strongly-typed model.

Alternatively, if you want to list them SEPARATELY, you could create a composite ViewModel

public class StudentsVM
{
public IEnumerable<Student_A> Student_A { get; set; }
public IEnumerable<Student_B> Student_B { get; set; }
}

var vm = new StudentsVM;
vm.Student_A = stud.Student_A.Where(...);
vm.Student_B = stud.STudent_B.Where(...);

ViewData.Model = vm;

Upvotes: 2

Related Questions