0

How can we pass following ViewModel - that is loaded via LINQ query's Select Statement - to a View. I'm getting the error shown below. Please note that I still want to load ViewModel via select statement of LINQ query:

Model:

Public class Customer
{
  Public int CustomerId {get; set;}
  Public string FullName {get; set;}
  ...
}

Public class Order
{
  Public int OrderId {get; set;}
  Public int CustomerId {get; set;}
  Public float Price {get; set;}
  ...
}

ViewModel:

Public class CustomViewModel
{
  Public String Name {get; set;}
  Public float Price {get; set;}
  ...
}

View:

@model myProject.Models.CustomViewModel
...

Controller:

var qry = from c in _context.Customers
          join o in context.Orders on c.CustomerId = o.CustomerId
          select new CustomViewModel { Name = c.FullName, Price = o.Price  };

return View(qry);

Error:

The model item passed into the ViewDataDictionary is of type 'Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[myProject.Models.CustomViewModel]. But this ViewDataDictionary instance requires a model item of type 'myProject.Models.CustomViewModel]'

nam
  • 21,967
  • 37
  • 158
  • 332
  • context._Customers is a list. Do you want the view to show a list or do you want to show a specific customer? – NineBerry Mar 03 '17 at 20:08
  • Your view is for a single `CustomViewModel` - its thats what you want then use `.FirstOrDefault()` in your query. (2nd code snippet in the dupe) –  Mar 03 '17 at 20:17
  • @StephenMuecke Thank for catching it. I had originally missed the second table in the post. I've added it now along with corresponding changes in the `ViewModel` and `LINQ` query – nam Mar 03 '17 at 20:26
  • @NineBerry To answer your question, please see my comment above – nam Mar 03 '17 at 20:30
  • 2
    Your edit makes no difference to the issue. You query is generating a collection of `CustomViewModel`, not a single `CustomViewModel`. Either your view needs to be `@model IEnumerable` to match the query, or if you want to have the view display just one item, then use `.FirstOrDefault()` to return one item. And do not use `var`! –  Mar 03 '17 at 20:32
  • @StephenMuecke Thanks. After reading your comment, I used `.SingleOrDefault()` and it worked. – nam Mar 03 '17 at 20:41

1 Answers1

2

You are passing to your view an IQueryable<CustomViewModel> not an instance of CustomViewModel as you intended to do. I think you want to get the list of names, so you should change the model type in your view to

@model IEnumerable<myProject.Models.CustomViewModel>

And also you should materialize your query before passing the result to your view:

return View(qry.ToList());

Otherwise when you try to hit the result of your query in your view, your DbContext will be disposed, so and an exception will be thrown.

Update

If you want to show the info related to one particular customer then I suggest you to use FirstOrDefault extension method:

return View(qry.FirstOrDefault());
ocuenca
  • 38,548
  • 11
  • 89
  • 102
  • Sorry I missed the second table in the POST. I've added it now along with the corresponding changes in the VM and LINQ query. You may want to modify your response accordingly. – nam Mar 03 '17 at 20:28
  • But in the View I just need to display a data about a single customer not a list. – nam Mar 03 '17 at 20:35
  • Then you you should call [FirstOrDefault](https://msdn.microsoft.com/en-us/library/bb549141(v=vs.110).aspx) method at the end of your query to select the customer you want to show,eg, `View(qry.FirstOrDefault());` – ocuenca Mar 03 '17 at 20:37