I'm wondering how to resolve the problem. I'm developing an ASP.NET MVC app
I have a models
public class SearcherString
{
public int ID { get; set; }
public string Description { get; set; }
public virtual ICollection<Path> Path { get; set;
public SearcherString()
{
Path = new List<Path>();
}
}
public class Path
{
public int ID { get; set; }
public int CategoryID { get; set; }
public string CategoryName { get; set; }
}
I'm passing it in my Controller (I'm writing my model into my database and then I'm retrieving it)
public ActionResult Index()
{
return View(db.SearchersString.ToList()
}
And I have a View with:
#model IEnumerable<App.Models.SearcherString>
The problem is in my View, I can't display the names from Path model
(CategoryID, CategoryName)
I tried to do:
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Description)
</th>
#foreach (var item in Model)
{
foreach (var path in item.Path)
{
<th>
#Html.DisplayName(path.CategoryID.ToString())
</th>
<th>
#Html.DisplayName(path.CategoryName)
</th>
}
}
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
#foreach (var path in item.Path)
{
<td>
#Html.DisplayFor(modelItem => path.CategoryID)
</td>
<td>
#Html.DisplayFor(modelItem => path.CategoryName)
</td>
}
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.ID }) |
#Html.ActionLink("Details", "Details", new { id = item.ID }) |
#Html.ActionLink("Delete", "Delete", new { id = item.ID })
</td>
</tr>
}
</table>
But I have only:
Could someone help me with this problem?
Edit:
Is there a way to change the Html.DisplayName to Html.DisplayNameFor here?
#Html.DisplayName(path.CategoryID.ToString())
You should include navigation property to your query:
public ActionResult Index()
{
return View(db.SearchersString.Include(c=>c.Path).ToList()
}
Your Model is incorrect.
public SearcherString()
{
Path = new List<Path>();
}
This is not a property. This is treated as a Method, a special one. And it is a constructor. That Creates a Path object That is EMPTY.
If you want to have a one to many relationship. You would have to use the property for this and add a property of ID.
public int PathID {get; set;}
public virtual Path Path{get; set;}
Now you have a lazy loading property that will automatically save the ID property of the Path class into your SearchString model property PathID.
to get the PathID, you will specifically need to call the include function if you're using EntityFramework, which most likely the case.
public ActionResult Index(){
return View(db.SearchersString.Include(c=>c.Path).ToList();
}
Related
I am having difficulty getting my Index view to display the values I have from the SQL database.
The main issue is that I cannot use #foreach (var item in Model) {... because my table is not created as Enumerable (I think). I run into the error message System.NullReferenceException: 'Object reference not set to an instance of an object.' pointing at Model in the foreach statement expression.
I am wondering if I need to set my table up as an Enumerable list, then display each item. Or if I am missing something with regards to my Index view. Or maybe I need to pass something through the Index return View()?
Here is the Image Model:
namespace Uploadimage.Models
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Web;
public partial class Image
{
public int Id { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
public string City { get; set; }
public string Province { get; set; }
public string Phone { get; set; }
[Required]
[RegularExpression(#"[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]{2,4}",
ErrorMessage = "Email doesn't look like a valid email address.")]
public string Email { get; set; }
[Compare("Email", ErrorMessage = "Emails do not match.")]
public string ConfirmEmail { get; set; }
[DisplayName("Upload File")]
public string ImagePath { get; set; }
public HttpPostedFileBase ImageFile { get; set; }
}
}
Here is the controller:
public class ImageController : Controller
{
[HttpGet]
public ActionResult Add()
{
return View();
}
[HttpPost]
public ActionResult Add(Image imageModel)
{
string fileName = Path.GetFileNameWithoutExtension(imageModel.ImageFile.FileName);
string extension = Path.GetExtension(imageModel.ImageFile.FileName);
fileName = fileName + DateTime.Now.ToString("yymmssfff") + extension;
imageModel.ImagePath = "~/Image/" + fileName;
fileName = Path.Combine(Server.MapPath("~/Image/"), fileName);
imageModel.ImageFile.SaveAs(fileName);
using(LoginDBEntities db = new LoginDBEntities())
{
db.Images.Add(imageModel);
db.SaveChanges();
}
ModelState.Clear();
return View();
}
[HttpGet]
public ActionResult View(int id)
{
Image imageModel = new Image();
using (LoginDBEntities db = new LoginDBEntities())
{
imageModel = db.Images.Where(x => x.Id == id).FirstOrDefault();
}
return View(imageModel);
}
public ActionResult Index()
{
return View();
}
}
And lastly, my Index View:
#model IEnumerable<Uploadimage.Models.Image>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.FirstName)
</th>
<th>
#Html.DisplayNameFor(model => model.LastName)
</th>
<th>
#Html.DisplayNameFor(model => model.City)
</th>
<th>
#Html.DisplayNameFor(model => model.Province)
</th>
<th>
#Html.DisplayNameFor(model => model.Phone)
</th>
<th>
#Html.DisplayNameFor(model => model.Email)
</th>
<th>
#Html.DisplayNameFor(model => model.ImagePath)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.FirstName)
</td>
<td>
#Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
#Html.DisplayFor(modelItem => item.City)
</td>
<td>
#Html.DisplayFor(modelItem => item.Province)
</td>
<td>
#Html.DisplayFor(modelItem => item.Phone)
</td>
<td>
#Html.DisplayFor(modelItem => item.Email)
</td>
<td>
#Html.DisplayFor(modelItem => item.ImagePath)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.Id }) |
#Html.ActionLink("Details", "Details", new { id=item.Id }) |
#Html.ActionLink("Delete", "Delete", new { id=item.Id })
</td>
</tr>
}
</table>
I have tried thoroughly looking this up but have found things that don't specifically apply to me.
Or I don't know what to look up.
Two things:
Your Index controller action will need to load the images to pass to the view. At a minimum to serve a collection of images as the view's "model":
public ActionResult Index()
{
using (LoginDBEntities db = new LoginDBEntities())
{
var images = db.Images.ToList();
return View(images);
}
}
Then in the view you will need to check whether you actually get any results, then extract your labels from the first result if there are any, or display a suitable message if there are no images:
<!-- ... -->
#if (Model.Any())
{
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.ElementAt(0).FirstName)
</th>
<th>
#Html.DisplayNameFor(model => model.ElementAt(0).LastName)
</th>
...
</tr>
#for (int count = 0; count < Model.Count; count++) {
<tr>
<td>
#Html.DisplayFor(model => model.ElementAt(count).FirstName)
</td>
<td>
#Html.DisplayFor(model => model.ElementAt(count).LastName)
</td>
...
<td>
#Html.ActionLink("Edit", "Edit", new { id=#Model.ElementAt(count).Id }) |
#Html.ActionLink("Details", "Details", new { id=#Model.ElementAt(count).Id }) |
#Html.ActionLink("Delete", "Delete", new { id=#Model.ElementAt(count).Id })
</td>
</tr>
}
</table>
}
else
{
<p> No Images. </p>
}
The above is written from memory so it will likely have some syntactic issues but it should point you in the right direction.
Typically when working with collections like search results I define a view model class for the results page that itself contains the collection of results. The page's model becomes that wrapper view model which can contain details about the page (such as things like current search criteria, lookup values for searches, etc.) along with the collection of results. (typically a PagedList to support pagination)
I.e.
[Serializable]
public class ImageIndexViewModel
{
public string NameSearchString { get; set; }
public ICollection<ImageViewModel> Results { get; set; } = new List<ImageViewModel>();
}
Where ImageViewModel is a serializable POCO view model to represent just the details about images that the view will display. Often the views don't need everything about a data row, and in cases where the data row has navigation properties and extra fields we don't need to display, serializing entities results in lazy load calls or simply sending a lot of extra data that isn't needed.
You don't have anything in your Index method which gets a list of entities.
Your Index method in your controller should look something like:
public ActionResult Index()
{
var model = db.Images.ToList();
return View(model);
}
This question already has answers here:
The model item passed into the dictionary is of type .. but this dictionary requires a model item of type
(7 answers)
Closed 5 years ago.
I get this Exception but i don't how to fix it:
The model item passed into the dictionary is of type 'System.Collections.Generic.List1[DataModel.Gabarit]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable1[ViewModel.GabaritViewModel]'.
My Controller:
public ActionResult Traitement(string designation)
{
GabaritRepository gabaritrepository = new GabaritRepository(db);
var gabarits = gabaritrepository.Get(g => g.Designation == designation).ToList();
return View(gabarits);
}
My View:
#model IEnumerable<ViewModel.GabaritViewModel>
#{
ViewBag.Title = "Traitement";
}
<h2>Traitement</h2>
<div class="col-xs-12">
<div class="box">
<h2>Gabarits</h2>
<table class="table table-striped">
<tr>
<th>
Code à barre
</th>
<th>
Etat
</th>
<th>
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.CodeBarre)
</td>
<td>
#Html.DisplayFor(modelItem => item.Etat)
</td>
<td>
#Html.ActionLink("Sortie", "Sortie", new {id = item.CodeBarre})
</td>
</tr>
}
</table>
</div>
</div>
GabaritViewModel:
namespace ViewModel
{
public class GabaritViewModel
{
public int CodeBarre { get; set; }
public string Designation { get; set; }
public string Photo { get; set; }
public Nullable<int> Produit { get; set; }
public Nullable<int> Poste { get; set; }
public string Exemplaire { get; set; }
public string Etat { get; set; }
public int Id_Etat { get; set; }
}
I have to pass ViewModel not DataModel and I don't know why I'm not allowed to.
Your repositories .Get() method is returning a collection of type Garbarit, you need a collection of type GabaritViewModel.
One option would be to do another select and manually map your properties:
public ActionResult Traitement(string designation)
{
GabaritRepository gabaritrepository = new GabaritRepository(db);
var gabarits = gabaritrepository.Get(g => g.Designation == designation)
//Map your Gabarit to your ViewModel here
.Select(x => new GabaritViewModel {
CodeBarre = x.CodeBarre,
Etat = x.Etat
}).ToList();
return View(gabarits);
}
When I create payment I want to display ClientName in my payment Index View. I get client name from another table called "Clients"
Payments Model:
public class Payments
{
[Key]
public int PaymentsId { get; set; }
public int ClientsId { get; set; }
[ForeignKey("ClientsId")]
public virtual Clients Clients { get; set; }
public String Paymentnumber { get; set; }
public DateTime PaymentDate { get; set; }
public Decimal Amount { get; set; }
public Decimal Discount { get; set; }
public String Reference { get; set; }
public String Bank { get; set; }
}
Payments controller:
// GET: Payments
public ActionResult Index()
{
return View(db.PaymentsList.ToList());
}
Payment Index View:
#model IEnumerable<localuh.Models.Payments>
....
<table class="table">
<tr>
<th>#Html.DisplayNameFor(model => model.Paymentnumber)</th>
<th>#Html.DisplayNameFor(model => model.PaymentDate)</th>
<th>#Html.DisplayNameFor(model => model.Amount)</th>
<th> #Html.DisplayNameFor(model => model.Discount)</th>
<th>#Html.DisplayNameFor(model => model.Reference)</th>
<th>#Html.DisplayNameFor(model => model.Bank)</th>
<th></th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>#Html.DisplayFor(modelItem => item.Paymentnumber)</td>
<td>#Html.DisplayFor(modelItem => item.PaymentDate)</td>
<td>#Html.DisplayFor(modelItem => item.Amount)</td>
<td>#Html.DisplayFor(modelItem => item.Discount)</td>
<td>#Html.DisplayFor(modelItem => item.Reference)</td>
<td>#Html.DisplayFor(modelItem => item.Bank)</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.PaymentsId }) |
#Html.ActionLink("Details", "Details", new { id=item.PaymentsId }) |
#Html.ActionLink("Delete", "Delete", new { id=item.PaymentsId })
</td>
</tr>
}
</table>
So, how can I do that?
Your Payments model contains a virtual property for Clients (which will be 'lazy loaded' by EF, so you simply need to add another table column to display the name of the client. Assuming your Clients model has a property public string Name { get; set; }, then it would be
<td>#Html.DisplayFor(modelItem => item.Clients.Name)</td>
Side note: Suggest you rename the property to Client, not Clients which suggests its a collection.
I am going to create a delete button for my table
here is my code
<center>
<H2>LIST OF REGISTERED STUDENTS</H2>
<br /><br />
</center>
<table class="table">
<tr>
<th>
Name
</th>
<th>
Last Name
</th>
<th>
E-Mail
</th>
<th>
Password
</th>
<th>
Student Number
</th>
<th>
Program
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.student_name)
</td>
<td>
#Html.DisplayFor(modelItem => item.student_lname)
</td>
<td>
#Html.DisplayFor(modelItem => item.student_email)
</td>
<td>
#Html.DisplayFor(modelItem => item.student_password)
</td>
<td>
#Html.DisplayFor(modelItem => item.student_number)
</td>
<td>
#Html.DisplayFor(modelItem => item.student_program)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.student_name }) |
#Html.ActionLink("Details", "Details", new { id=item.student_name }) |
#Html.ActionLink("Delete", "Delete", new { id=item.student_name })
</td>
</tr>
}
</table>
but when I create the delete syntax
public ActionResult Delete(int id = 0)
{
CSdbConnectionString db = new CSdbConnectionString();
student student = db.students.Find(id);
if(student == null)
{
return HttpNotFound();
}
return View(student);
}
// POST: Student/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
CSdbConnectionString db = new CSdbConnectionString();
try
{
student student = db.students.Find(id);
db.students.Remove(student);
db.SaveChanges();
return RedirectToAction("ViewStudents","ConsulSked");
}
catch
{
return View();
}
}
the code db.students.Find(id) has an error of
Cannot implicitly convert type CS.Models.student to CS.student
here is my student class
[Table("student")]
public class student
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int student_id { get; set; }
public string student_name { get; set; }
public string student_lname { get; set; }
public string student_email { get; set; }
public string student_password { get; set; }
public string student_number { get; set; }
public string student_program { get; set; }
}
and this is my data context class
public class CSdbConnectionString : DbContext
{
public CSdbConnectionString()
: base("CSdbConnectionString")
{ }
public DbSet<appointment> appointments { get; set; }
public DbSet<faculty> faculties { get; set; }
public DbSet<sched> scheds { get; set; }
public DbSet<student> students { get; set; }
}
what should I do? I can't create the delete option.
I have found the solution, for those in the future who will have the same error.
It is because I have a .dbml file in my project so I can store my stored procedures. That is the
CS.student
the one in my namespace model is the
CS.Models.student
and that's the one we need.
So instead of
student student = db.students.Find(id);
make it
CS.Models.student student = db.students.Find(id);
I have spent the past day and a half trying to find this answer and sometimes it seems like I am so close but so far no luck.
I have a controller where I defined a LINQ query and am trying to figure out how to pass the results onto a listing view. the following is the Controller code:
namespace CMS.Controllers
{
public class SurveyController : Controller
{
private SupportEntities supdb = new SupportEntities();
private BuisnessEntities bsdb = new BuisnessEntities();
//
// GET: /Survey/BizSurveyC
public ViewResult BizSurveyC(string nipaKey, string bOrg)
{
// use the next two lines for testing and then either delete or comment them out.
nipaKey = "22";
bOrg = "MPC";
var Cquery = from Mstr in bsdb.BizOrgInsts
join Dat in bsdb.BizSurveyQ on Mstr.ID equals Dat.MASTERID
where Mstr.NIPAKEY == nipaKey & Mstr.FULCIRCORG == bOrg
orderby Mstr.STREETSUFX, Dat.ADDRESS, Mstr.NUMBER
select new { MasterId = Mstr.ID, Name = Mstr.OLDNAME, Mstr.ADDRESS, Mstr.NIPAKEY, Dat.SURVEYDATE, SurveyId = Dat.ID, Dat.RESURVEYOF, Dat.STAMP };
//ViewBag.BizQuery = Cquery;
ViewData["BizQuery"] = new SelectList(Cquery);
return View();
}
}
}
As you can tell by looking I have tried ViewData and Viewbag but so far with no luck
Here are the way things are now appearing:
ViewModel Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace CMS.Models
{
public class BizSurveyCVM
{
public long? MasterId { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string NipaKey { get; set; }
public string Date { get; set; }
public long? SurveyId { get; set; }
public long? Resurvey { get; set; }
public string DateStamp { get; set; }
}
}
Modified Action
var Cquery = (from Mstr in bsdb.BizOrgInsts
join Dat in bsdb.BizSurveyQ on Mstr.ID equals Dat.MASTERID
where Mstr.NIPAKEY == nipaKey & Mstr.FULCIRCORG == bOrg
orderby Mstr.STREETSUFX, Dat.ADDRESS, Mstr.NUMBER
select new BizSurveyCVM
{
MasterId = Mstr.ID,
Name = Mstr.OLDNAME,
Address = Mstr.ADDRESS,
NipaKey = Mstr.NIPAKEY,
Date = Dat.SURVEYDATE,
SurveyId = Dat.ID,
Resurvey = Dat.RESURVEYOF,
DateStamp = Dat.STAMP
}).ToList();
return View(Cquery);
}
BizSurveyC View
#model List<CMS.Models.BizSurveyCVM>
<table>
<tr>
<th>
MasterId
</th>
<th>
Name
</th>
<th>
Address
</th>
<th>
NipaKey
</th>
<th>
Date
</th>
<th>
SurveyId
</th>
<th>
Resurvey
</th>
<th>
DateStamp
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.MasterId)
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Address)
</td>
<td>
#Html.DisplayFor(modelItem => item.NipaKey)
</td>
<td>
#Html.DisplayFor(modelItem => item.Date)
</td>
<td>
#Html.DisplayFor(modelItem => item.SurveyId)
</td>
<td>
#Html.DisplayFor(modelItem => item.Resurvey)
</td>
<td>
#Html.DisplayFor(modelItem => item.DateStamp)
</td>
</table>
here is the resulting view:
SORRY NOT ALLOWED TO SAVE IMAGE YET BUT IN THE VIEW I HAVE HEADERS BUT NO DATA.
I obviously have some work to do in the view or maybe the query but things are looking much better thanks so everyone's help. Thank you very much
You could create a ViewModel class to hold whatever your query results are and then strongly type your view for the new ViewModel class:
ViewModel Class:
public class BizSurveyCVM
{
public long MasterId { get; set; }
public string Name { get; set; }
...
}
Modified Action:
var Cquery = (from Mstr in bsdb.BizOrgInsts
join Dat in bsdb.BizSurveyQ on Mstr.ID equals Dat.MASTERID
where Mstr.NIPAKEY == nipaKey & Mstr.FULCIRCORG == bOrg
orderby Mstr.STREETSUFX, Dat.ADDRESS, Mstr.NUMBER
select new BizSurveyCVM { MasterId = Mstr.ID, Name = Mstr.OLDNAME, ...}
).ToList();
return View(Cquery);
BizSurveyC View
#model List<{namespace}.BizSurveyCVM>
#foreach(var item in Model) {
{HTML Mark-up}
}
EDIT: Here's an updated example of the view based on the updated question:
#model List<{namespace}.BizSurveyCVM>
#foreach(var item in Model) {
<tr>
<td>
#item.MasterId
</td>
<td>
#item.Name
</td>
<td>
#item.Address
</td>
...
</tr>
}
return View(Cquery);
or
return View("ViewName",Cquery);
and then in your view, the model type should match the type of Cquery. But I find that its easier (assuming you're using VS) to just right click in the method body somewhere and click "add view", and select the model from the list of model types.
Are you sure that you want do?
it's more useful the collection in the view, so you can build anything you need, like a select list.
don't forget define who is your datavalue and displayvalue in the select list, like..
ViewData["BizQuery"] = new SelectList(Cquery, null, "MasterId", "Name");
Ok, your code works for me, so check your view, you must do the correct cast of your object in the viewdata
you need have something like this
#foreach (SelectListItem item in (SelectList)ViewData["BizQuery"])
{
<p>#item.Text</p>
}