Question

I currently have the following code in the HomeController of my MVC project:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        MyDataContext dc = new MyDataContext();

        IQueryable<Table1Data> j =
            from n in dc.Table1                     
            select n;

        return View(j);
    }

So that works okay, but now I want to pass a second table through to the same view. So I was thinking I should be able to do something like this:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        MyDataContext dc = new MyDataContext();

        IQueryable<Table1Data> j =
            from n in dc.Table1                     
            select n;

        IQueryable<Table2Data> l =
            from k in dc.Table2        
            select k;

        return View(j, l);
    }

Is there a way to have the view accept two models like this or, alternatively, a way to merge the two result sets (the two tables are not linked in any way?

Was it helpful?

Solution

Yes there is, but not quite like that. The way to do what you wish to do is to create a custom ViewModel class. This class (MyPageViewModel) would have two (or more) properties, one for each of your objects. In your view, you would access them using Model.Table1Data and Model.Table2Data.

A custom ViewModel class is very simple:

public class MyPageViewModel
{
   public IQueryable<Table1Data> Table1Data { get; set; }
   public IQueryable<Table2Data> Table2Data { get; set; }
}

You view would need to be strongly typed to this custom ViewModel class.

<%@ Page Title="MyPage" MasterPageFile="~/Application/Master Pages/Site.Master"
    Inherits="System.Web.Mvc.ViewPage(Of MyAppNamespace.MyPageViewModel)" %>

Don't try to type that youself; easier to create a new view and check "strongly typed" view, and specify your New Custom Viewmodel class.

Then your action Controller method would be:

public class HomeController : Controller
{
  public ActionResult Index()
  {
    MyDataContext dc = new MyDataContext();

    MyPageViewModel vm = new MyPageViewModel();

    vm.Table1Data =  from n in dc.Table1                     
                     select n;

    vm.Table1Data = from k in dc.Table2        
                    select k;

    return View(vm);
  }
}

OTHER TIPS

Yes - create a new class - which you will use as your model - that contains both tables:

public class MyModel {
   public IQueryable<Table1Data> Table1Data { get; set; }
   public IQueryable<Table2Data> Table2Data { get; set; }
}

Then, in your controller, initialize this class and populate both properties and send it to your view. Then, modify the view to recognize this new type as the view model.

Why don't you add a class in your models for this?

public class MyModel {

public j {get; set;}
public l {get; set;}

}

Then you pass MyModel to the view on the View's Head.

On the controller:

public ActionResult Index() { MyDataContext dc = new MyDataContext();

    IQueryable<Table1Data> j =
        from n in dc.Table1                     
        select n;

    IQueryable<Table2Data> l =
        from k in dc.Table2        
        select k;

    MyModel myclass = new MyModel();
    myclass.j = j;
    myclass.l = l;

    return View(myclass);
}

I solved the problem by creating a list of 'tables' and passing this to my view model. This is essentially a list of a list of TransactionEntities. FYI, my solution was named DAL, and in the models I created a TransactionEntity to represent a transaction.

    private TransactionEntity te;
    private IEnumerable<TransactionEntity> tel1; // A list of TransactionEntities
    private IEnumerable<TransactionEntity> tel2;
    private IEnumerable<TransactionEntity> tel3;
    private IEnumerable<IEnumerable<TransactionEntity>> telCollection;

I populate the transaction entity lists (tel1, tel2, tel3) with my te 'rows', then add the three 'tel' objects (like a table essentially) to my telCollection and assign this to my ViewData.Model.

    telCollection = new List<IEnumerable<TransactionEntity>>();
    telCollection = telCollection.Concat(new[] { tel1 });
    telCollection = telCollection.Concat(new[] { tel2 });
    telCollection = telCollection.Concat(new[] { tel3 });
    ViewData.Model = telCollection;
    return View();

In the ASPX file, I then get the list and iterate through each 'table' (ElementAt(#)), creating three different columns, one for each of the tal 'tables'. BTW, you can ignore the counter variable.

<td>
   <% int counter = 0; %>
   <% IEnumerable<IEnumerable<DAL.Models.TransactionEntity>> tranlist = 
          (IEnumerable<IEnumerable<DAL.Models.TransactionEntity>>)ViewData.Model; %>

   <% foreach (DAL.Models.TransactionEntity te in tranlist.ElementAt(0))
      {.... create rows/columns as needed for the data in a HTML sub-table ......} %>
 </td>
 <td>
    <% counter = 0; %>
    <% foreach (DAL.Models.TransactionEntity te in tranlist.ElementAt(1))
      {..........} %>
 </td>
 <td>
    <% counter = 0; %>
    <% foreach (DAL.Models.TransactionEntity te in tranlist.ElementAt(2))
      {..........} %>
 </td>

You could make them both into a single ViewModel:

Model Definition:

public class YourModelName
{
       public IQueryable<Table1Data> FirstTableData { get; set;}
       public IQueryable<Table2Data> SecondTableData { get; set;}

       public YourModelName(IQueryable<Table1Data> d1, IQueryable<Table2Data> d2)
       {
            this.FirstTableData = d1;
            this.SecondTableData = d2;
       }
}

Usage (in Controller):

public ActionResult Index()
    {
        MyDataContext dc = new MyDataContext();

        IQueryable<Table1Data> j =
            from n in dc.Table1                     
            select n;

        IQueryable<Table2Data> l =
            from k in dc.Table2        
            select k;

         YourModelName model = new  YourModelName(j, l);

        return View(model);
    }

In pre-MVC3 I would have used a ViewModel and add properties for each object you want the view to use. If you're using MVC3 I'd take a look at ViewBag.

A simple view model:

public class SomeViewModel
{
   public object Object1 { get; set; }
   public string Message { get; set; }
}

Then in your controller you'd pass this to your view:

var vm = new SomeViewModel { Object1 = coolThing, Message = neatMessage };
return View(vm);

You will probably have to use ViewModel. You define class, that will contain instances of both classes you want (+ any other additional properties), and then you use this as a model.

class NewViewModel {
    Table1 T1 {get;set;}
    Table2 T2 {get;set;}
    int Anything {get;set;}
}

Then you just prepare collection of these ViewModel classes and later access instances of them like:

NewViewModel m = new NewViewModel();
var a = m.T1.PropertyA;
var b = m.T2.PropertyB;

etc.. Just merge all entities you need into one class and use this class as your model in Controller and View.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top