I'm trying to print out data from an SQL query, but I'm running into error after error.
Bassically what Im trying to do is fetch some data from teachers out of a database, and then make a list of them on my view. However everytime I try to print, I get this error
ViewModel' does not contain a definition for 'FirstName' and no
extension method 'FirstName' accepting a first argument of type
'ViewModel' could be found.
Here's my code;
ViewModel
namespace Ability.Models
{
public class ViewModel
{
public virtual IEnumerable<Teacher> Teachers { get; set; }
public Teacher Teacher { get; set; }
public virtual IEnumerable<Skill> Skills { get; set; }
public Skill Skill { get; set; }
}
}
Controller
public ActionResult Index()
{
string campus = Request.Params["Campus"];
if (campus != null)
{
if (campus == "Alle")
{
var teachers = (from t in db.Teachers
select t);
}
else
{
var teachers = (from t in db.Teachers
where t.Campus == campus
select t );
}
}
else
{
var teachers = (from t in db.Teachers
select t);
}
var Model = new ViewModel
{
Teachers = db.Teachers.ToList(),
};
return View(Model);
}
View
#model IEnumerable<Ability.Models.ViewModel>
<h2>Teachers at Thomas More</h2>
...
#foreach (var Teacher in Model)
{
<tr>
<td>
#Teacher.FirstName
</td>
<td>
#Teacher.LastName
</td>
<td>
#Teacher.Email
</td>
<td>
#Teacher.Campus
</td>
</tr>
}
I'm not sure if it mathers, but I already tried doing several things including changing my loop to
#foreach (var Teacher in Model.Teachers)
but then I receive a similar error
'IEnumerable' does not contain a definition for 'Teachers'
and no extension method 'Teachers' accepting a first argument of type
'IEnumerable' could be found
Looking forward to any help I can receive!
I see a couple of things that doesn't make sense.
First of all, where do you use the teachers?
Personally, I think that the following code is more reasonable:
public ActionResult Index()
{
IEnumerable<Teacher> teachers = Enumerable.Empty<Teacher>();
string campus = Request.Params["Campus"];
if (campus != null)
{
if (campus == "Alle")
{
teachers = (from t in db.Teachers
select t);
}
else
{
teachers = (from t in db.Teachers
where t.Campus == campus
select t );
}
}
else
{
teachers = (from t in db.Teachers
select t);
}
var Model = new ViewModel
{
Teachers = teachers
};
return View(Model);
}
Second, you have to initialize also the other properties of ViewModel in the above action method.
Now let's go to the view. You pass there a model of type ViewModel. When you want to iterate through the teachers sequence, you can try this:
#foreach (var teacher in Model.Teachers)
{
<tr>
<td>
#teacher.FirstName
</td>
<td>
#teacher.LastName
</td>
<td>
#teacher.Email
</td>
<td>
#teacher.Campus
</td>
</tr>
}
All the above makes sense provided that db.Teachers is an IEnumerable<Teacher>.
You're sending the type ViewModel to the view:
var Model = new ViewModel
{
Teachers = db.Teachers.ToList(),
};
return View(Model);
But it's expecting the type IEnumerable<Ability.Models.ViewModel>:
#model IEnumerable<Ability.Models.ViewModel>
That is, it's expecting a collection where you're providing an object.
Given the usage in the view, it seems like you should just change it to expect a single object:
#model Ability.Models.ViewModel
This would allow you to directly access the property you're looking for:
#foreach (var Teacher in Model.Teachers)
Side Note: The logic in your controller doesn't look correct. You conditionally create a teachers variable, but then never use it. Instead, you just materialize all of the teachers in the database and send them all to the view. If you intend to see all of the teachers, you can remove most of that code. If you intend to see specific teachers, you would want to use the variable you created. Reference #Christos' answer for a practical example of that.
Your model is a list of ViewModels. You needed to use #foreach (var Teacher in Model.Teachers).
Related
my index view has a model that looks like this:
#model IEnumerable<WebSurvey.Data.Models.Question>
and is used by this:
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Question1)
</td>
<td>
#Html.DisplayFor(modelItem => item.ReplyOptions)
</td>
<td>
#Html.DisplayFor(modelItem => item.Group)
</td>
<tr>
}
</tbody>
but i also need a model that looks like this:
#model WebSurvey.Data.Models.Question
so that I can use the properties of "Questions" in "asp-for" to create a new Question, because it does not work with the current model.
My question: Is there a way to create another model in my view?
Hope you can help me out :)
You should consider always creating a model with a name that corresponds with your view instead of focusing first on what data you might be going to display.
If your view is called Questions, you should create a model called QuestionsViewModel.
public class QuestionsViewModel { }
After that, you can think about what data you want to add, so if you have a list of questions add it to the class as a property.
public class QuestionsViewModel
{
public IEnumerable<Question> Questions { get; set; }
}
/// In your view
#foreach (var question in Model.Questions)
{
}
Later you decide you also need a User.
public class QuestionsViewModel
{
public IEnumerable<Question> Questions { get; set; }
public User User { get; set; }
}
/// In your view
<span>#Model.User.Username</span>
#foreach (var question in Model.Questions)
{
}
The point is, you can now add as many properties as you like.
You shouldn't try to add a 2nd model. You want to wrap the 2 models in a parent model.
public class BlueprintFor {
public IEnumerable<Question> Questions {get;set;}
public Question Question {get;set;}
}
If you further struggle with using the wrap model to create a form, separate the wrap model by passing one of the child models in to a partial view which contains the form.
I'been trying to figure this out but can't.
I've got a model which has let's say a one-to-many relationship.
public virtual IList<ListModels.listaIdInstrumentos> listaIdInstrumentos { get; set; }
A pretty plane controller:
public ActionResult Index()
{
informeModelContext db = new informeModelContext();
var model = db.Informe.ToList();
return View(model);
}
And a scaffolded View:
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.listaCalibracion)
</td>
...
The "listaCalibracion" is a List of string that for example could be something like 2 strings named "ABC" and "XYZ"
although i CAN display the values correctly in my page, it will display ("ABCXYZ") and what i want to show is (ABC /n/n XYZ) meaning one under another.
Sorry if i can't make myself clear. English is not my first Lenguage.
Could you help me?
Thanks!
#foreach (var item in Model)
{
#foreach (var subItem in item.listaCalibracion)
{
<tr>
<td>
#Html.DisplayFor(modelItem => subItem )
</td>
I'm trying to get data from 2 table using Linq , that one table had FK to the second table but not necessary has data (table review could have for each review comments (many)) what i'm trying to get is: in a single view get all the reviews and if there are any comments display them related to the review Id
trying to use join get me error in my view (model pass is wrong i tried each table model) this is my code :
public ActionResult ttt()
{
var model = from rev in db.reviews
join com in db.Comments
on rev.ReviewId equals com.ReviewId into JoineRevCom
from com in JoineRevCom.DefaultIfEmpty()
select new
{
rev.ReviewBody,
rev.ReviewHeadLine,
Comments = com != null ? com.CommentBody : null
};
return View(model);
}
#model IEnumerable< SiteMvcPro.Models.Review>
As always I would start by writing a view model for this view containing the information that I would like to display and never send anonymous objects to your view like you did in your code.
Let's suppose that you want to display a list of reviews and for each review the list of corresponding comments. So your view model might look something along those lines:
public class ReviewViewModel
{
public int ReviewId { get; set; }
public string ReviewBody { get; set; }
public string ReviewHeadLine { get; set; }
public IList<CommentViewModel> Comments { get; set; }
}
public class CommentViewModel
{
public string CommentBody { get; set; }
}
with this defined you could perform your LINQ query to extract the necessary data and project to this view model:
IEnumerable<ReviewViewModel> viewModel =
from review in db.reviews
join comment in db.Comments
on review.ReviewId equals comment.ReviewId into joinedReviewComment
select new ReviewViewModel // <-- Always project to a view model and never to an anonymous object
{
review.ReviewBody,
review.ReviewHeadLine,
Comments = joinedReviewComment.Select(c => new CommentViewModel
{
CommentBody = c.CommentBody,
}).ToList(),
};
return View(viewModel.ToList()); // <-- Always pass a view model to your view
And now all that's left is to display this information in your strongly typed view:
#model IList<ReviewViewModel>
<table>
<thead>
<tr>
<th>Review id</th>
<th>Review body</th>
<th>Review headline</th>
<th>Review comments</th>
</tr>
</thead>
<tbody>
#for (var i = 0; i < Model.Count; i++)
{
<tr>
<td>#Html.DisplayFor(x => x[i].ReviewId)</td>
<td>#Html.DisplayFor(x => x[i].ReviewBody)</td>
<td>#Html.DisplayFor(x => x[i].ReviewHeadLine)</td>
<td>
#for (var j = 0; j < Model[i].Comments.Count; j++)
{
<div>
#Html.DisplayFor(x => x[i].Comments[j].CommentBody)
</div>
}
</td>
</tr>
}
</tbody>
</table>
This being said projecting is one thing but filtering your data is another. Suppose that you have millions of reviews and each review has millions of comments. Making the aforementioned query will simply bring your server down pretty quickly. So think about that when designing your application and views. Don't hesitate to use the Where, Skip and Take operators to filter your result-sets down into a meaningful collection of data that is reasonable enough to be displayed on a single view.
This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 8 years ago.
Can anyone help me with this:
I need to display dynamic data in my _DeliveryDetailsPatial.cshtml. This is called every time the user is in the Delivery Information page or New Address page. Every time I am to navigate to either of these pages i keep getting this ERROR:
Object reference not set to an instannce of an object
How can I solve this?
Thank you!
Here's my code:
_DeliveryDrtailsPartial:
#model QuiznosOnlineOrdering.Models.StoreViewModel
<table id="orderTable" class="table">
<tr>
<td class="t">Item</td>
<td class="t">Quantity</td>
<td class="t">Item Price</td>
</tr>
#foreach (var item in Model.StoreAddress)
{
<tr>
<td>#Html.DisplayFor(model => item.NOM)</td>
<td>#Html.DisplayFor(model => item.ADRESSE)</td>
<td>#Html.DisplayFor(model => item.VILLE)</td>
</tr>
}
</table>
StoreViewModel:
public IEnumerable<Store> StoreAddress { get; set; }
public IEnumerable<StoreHour> StoreHour { get; set; }
public IEnumerable<ReferenceAcceptedPayment> StoreAcceptedPayment { get; set; }
DeliveryController:
[HttpGet]
public ActionResult GetStoreDetails()
{
StoreViewModel store = new StoreViewModel();
store.StoreAddress = from s in db.Store
select s;
return View();
}
[HttpGet]
public ActionResult GetStoreDetails()
{
StoreViewModel store = new StoreViewModel();
store.StoreAddress = from s in db.Store
select s;
return View(store);
}
You haven't passed model
You are never actually injecting the model into the view.
[HttpGet]
public ActionResult GetStoreDetails()
{
StoreViewModel store = new StoreViewModel();
store.StoreAddress = from s in db.Store
select s;
return View(store);
}
As a result, when you try to read properties on your model, you get an exception since the model is null.
You need to pass the model like this
[HttpGet]
public ActionResult GetStoreDetails()
{
StoreViewModel store = new StoreViewModel();
store.StoreAddress = from s in db.Store
select s;
return View(store);
}
Also following are the links which will help you also in passing views to partial view also.
return PartialView("_ViewPage",model);
Setting models in asp.net mvc views and partial views
I am using the following code for a master view model that contains two lists of data,
namespace trsDatabase.Models
{
public class masterViewModel
{
public IEnumerable <Customer> Customers { get; set; }
public IEnumerable <CustomerSite> CustomerSites { get; set; }
}
}
I am using the following code to pass the veiwmodel to the view,
public ViewResult Index()
{
masterViewModel sitesModel = new masterViewModel();
return View(sitesModel);
}
Then in my view I have the following,
#model IEnumerable<trsDatabase.Models.masterViewModel>
foreach (var site in customer.CustomerSites)
{
foreach (var cust in customer.Customers)
{
<tr>
<td>
#cust.CustomerName
</td>
<td>
#site.UnitNo
</td>
using the above code I am able to access all properties from the two lists in the viewmodel, however when I navigate to the view I get an error as the view is expecting an IEnumerable. If I change the declaration to just pass the viewmodel
#model trsDatabase.Models.masterViewModel
the foreach statement won't work, it gives this error
The model item passed into the dictionary is of type 'trsDatabase.Models.masterViewModel', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[trsDatabase.Models.masterViewModel]'.
Can anyone offer any advice or point me in the right direction for resolving this, is it possible to make my viewmodel IEnumerable?
Change this
#model IEnumerable<trsDatabase.Models.masterViewModel>
to this
#model trsDatabase.Models.masterViewModel
You are passing in a single instance of masterViewModel, so your view should expect a single instance, which is exactly what the error is telling you if not in a cryptic way.
Yes You can...
in you Model (masterViewModel) make the Customers and CustomerSites List like this:
namespace trsDatabase.Models
{
public class masterViewModel
{
public List<Customer> Customers { get; set; }
public List<CustomerSite> CustomerSites { get; set; }
}
}
in the same Model, define a method that would return IEnumerable like this:
public IEnumerable<Customer> Getall()
{
List<Customer> lcustomer= new List<Customer>();
//Get Customer data from Database or wherever
lcustomer.Add(new Customer{ firstname= "Quentin ", lastname= "tarantino" });
return lcustomer;
}
In your controller, instantiate your Model. then call Getall() method which would return IEnumerable basically a list of customers, and pass it to your View
var rep = new masterViewModel();
var model = rep.Getall();
return View(model);