-->

MVC - Passing multiple data tables to a view

2019-01-18 06:36发布

问题:

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?

回答1:

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);
  }
}


回答2:

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.



回答3:

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);
}


回答4:

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>


回答5:

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);
    }


回答6:

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);


回答7:

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.