Show data from other model in my View - c#

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.

Related

ASP.NET Core 5 MVC Using View Models with enumeration

I have 2 models; TypeOne and Project_Screen. I need a view that makes 2 tables with information from both of those tables. I tried to use this guide to making a view model which helped but isnt doing quite the same thing I am: https://dotnettutorials.net/lesson/view-model-asp-net-core-mvc/
This is the View Model I made:
public class MyProjectsViewModel
{
public Project_Screen Project_Screen { get; set; }
public TypeOne TypeOne { get; set; }
}
This is the controller:
public class ProfileController : Controller
{
private readonly Natural_ResourcesContext _context;
public ProfileController(Natural_ResourcesContext context)
{
_context = context;
}
// GET: Profile
public ActionResult Index()
{
Project_Screen project_Screen = (Project_Screen)(from s in _context.Project_Screen
where s.DSN_PM == User.Identity.Name
select s);
TypeOne typeOne = (TypeOne)(from x in _context.TypeOne
where x.Name == User.Identity.Name
select x);
MyProjectsViewModel myProjectsViewModel = new MyProjectsViewModel()
{
Project_Screen = project_Screen,
TypeOne = typeOne
};
return View(myProjectsViewModel);
}
}
As you can see, project_Screen and typeOne are all records in which Manager = Name.
Then in the view I'd like to display these something like this:
#model EnvApp.ViewModels.MyProjectsViewModel
#{
ViewData["Title"] = "Projects";
}
<h1>My Projects</h1>
<hr />
<h4>Screening Forms</h4>
<table class="table">
<thead>
<tr>
<th>
State Project Number
</th>
<th>
Federal Project Number
</th>
<th>
Project Name
</th>
<th>
County
</th>
<th>
Coordinates
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.State_Project_Number)
</td>
<td>
#Html.DisplayFor(modelItem => item.Federal_Project_Number)
</td>
<td>
#Html.DisplayFor(modelItem => item.Project_Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.County)
</td>
<td>
#Html.DisplayFor(modelItem => item.Coordinates)
</td>
<td>
<a asp-action="Details" asp-route-id="#item.ID">Details</a>
</td>
</tr>
}
</tbody>
</table>
<br />
<hr />
<h4>Type One Projects</h4>
<table class="table">
<thead>
<tr>
<th>
State Project Number
</th>
<th>
Federal Project Number
</th>
<th>
Project Name
</th>
<th>
County
</th>
<th>
Coordinates
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.State_Project_Number)
</td>
<td>
#Html.DisplayFor(modelItem => item.Federal_Project_Number)
</td>
<td>
#Html.DisplayFor(modelItem => item.Project_Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.County)
</td>
<td>
#Html.DisplayFor(modelItem => item.Coordinates)
</td>
<td>
<a asp-action="Details" asp-route-id="#item.ID">Details</a>
</td>
</tr>
}
</tbody>
</table>
I get the compiler error CS1579 on ````Model```:
foreach statement cannot operate on variables of type 'MyProjectsViewModel' because 'MyProjectsViewModel' does not contain a public instance or extension definition for 'GetEnumorator'
Which I think makes sense, because I have not denoted Project_Screen or TypeOne as an object that holds multiple records, but I'm not quite sure how to do this.
Am I on the right track or have I misunderstood this? What am I missing?
EDIT 1:
I did exactly what Md Farid Uddin Kiron said so the code in his answer reflects my view model and view. However I am still having issues with my controller.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using EnvApp.ViewModels;
using EnvApp.Models.DB;
namespace EnvApp.Controllers
{
public class ProfileController : Controller
{
private readonly Natural_ResourcesContext _context;
public ProfileController(Natural_ResourcesContext context)
{
_context = context;
}
// GET: Profile
public ActionResult Index()
{
Project_Screen project_Screen = (Project_Screen)(from s in _context.Project_Screen
where s.DSN_PM == User.Identity.Name
select s);
TypeOne typeOne = (TypeOne)(from x in _context.TypeOne
where x.Name == User.Identity.Name
select x);
MyProjectsViewModel myProjectsViewModel = new MyProjectsViewModel()
{
Project_Screen = project_Screen,
TypeOne = typeOne
};
return View(myProjectsViewModel);
}
}
}
The issue is that project_Screen and typeOne aren't lists or IEnumerable types, which makes sense, but I'm not the syntax to get them to be enumerable.
IF you need to see it, here is my view model:
public class MyProjectsViewModel
{
public List<Project_Screen> Project_Screen { get; set; }
public List<TypeOne> TypeOne { get; set; }
}
And here is the View:
<h1>My Projects</h1>
<hr />
<h4>Screening Forms</h4>
<table class="table">
<thead>
<tr>
<th>
State Project Number
</th>
<th>
Federal Project Number
</th>
<th>
Project Name
</th>
<th>
County
</th>
<th>
Coordinates
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.Project_Screen)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.State_Project_Number)
</td>
<td>
#Html.DisplayFor(modelItem => item.Federal_Project_Number)
</td>
<td>
#Html.DisplayFor(modelItem => item.Project_Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.County)
</td>
<td>
#Html.DisplayFor(modelItem => item.Coordinates)
</td>
<td>
<a asp-action="Details" asp-route-id="#item.ID">Details</a>
</td>
</tr>
}
</tbody>
</table>
<br />
<hr />
<h4>Type One Projects</h4>
<table class="table">
<thead>
<tr>
<th>
State Project Number
</th>
<th>
Federal Project Number
</th>
<th>
Project Name
</th>
<th>
County
</th>
<th>
Coordinates
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.TypeOne)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.State_Project_Number)
</td>
<td>
#Html.DisplayFor(modelItem => item.Federal_Project_Number)
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.County)
</td>
<td>
#Html.DisplayFor(modelItem => item.Coordinates)
</td>
<td>
<a asp-action="Details" asp-route-id="#item.ID">Details</a>
</td>
</tr>
}
</tbody>
</table>
Again, the issue is that project_Screen and typeOne aren't lists or IEnumerable types IN THE CONTROLLER. They are Lists in actuallity and everywhere EXCEPT the controller but they need to be. The error is on the lines
MyProjectsViewModel myProjectsViewModel = new MyProjectsViewModel()
{
Project_Screen = project_Screen,
TypeOne = typeOne
};
on project_Screen and typeOne and reads
cannot implicitly convert type Envapp.Models.DB.Project_Screen to System.Collection.Generic.List<Envapp.Models.DB.Project_Screen>
This appears to be happening because the code there is trying to point to the DB model table for Project_Screen rather than the ViewModel representation of items in the Project_Screen model. How do I fix this?
EDIT 2:
I'm not sure what it is but something in my code seems to be really confusing people. I am posting all of my models for clarification:
Project_Screen.cs
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
#nullable disable
namespace EnvApp.Models.DB
{
public partial class Project_Screen
{
[Key]
public long ID { get; set; }
public string State_Project_Number { get; set; }
public string? Federal_Project_Number { get; set; }
public string Project_Name { get; set; }
public string County { get; set; }
public DateTime? Memo_Date { get; set; }
public string From { get; set; }
public string? Authorization { get; set; }
public string DSN_PM { get; set; }
public string? History { get; set; }
public string History_PM { get; set; }
public bool Review_Exempt_H { get; set; }
public bool SHPO_Approval_H { get; set; }
public string? Archaeology { get; set; }
public string Archaeology_PM { get; set; }
public bool Review_Exempt_A { get; set; }
public bool SHPO_Approval_A { get; set; }
public bool ESA_Key { get; set; }
public bool Crayfish { get; set; }
public bool Crayfish_Habitat_Assessment { get; set; }
public bool NLEB_4D { get; set; }
public bool USFWS { get; set; }
public string USFWS_Type { get; set; }
public bool Mussel_Habitat { get; set; }
public bool Mussel_Stream { get; set; }
public string Within_Airport { get; set; }
public string? ToPo_Quad_Name { get; set; }
public bool Bat_Habitat { get; set; }
public string? Bars { get; set; }
public string Coordinates { get; set; }
public string? Natural_Resources_Notes { get; set; }
public string Adduser { get; set; }
public DateTime? Date_Added { get; set; }
public string Crayfish_Notes { get; set; }
public string Mussel_Notes { get; set; }
}
}
TypeOne.cs
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
#nullable disable
namespace EnvApp.Models.DB
{
[Table("Type_One")]
public partial class TypeOne
{
[Key]
public long ID { get; set; }
[MaxLength(50)]
public string State_Project_Number { get; set; }
[MaxLength(50)]
public string Federal_Project_Number { get; set; }
[MaxLength(50)]
public string Name { get; set; }
[MaxLength(50)]
public string Route_Number { get; set; }
public string County { get; set; }
[MaxLength(50)]
public string Work_Type { get; set; }
[MaxLength(100)]
public string Coordinates { get; set; }
public string Project_Description { get; set; }
public bool? Federal_Aid { get; set; }
public bool? Minimal_Project_Verification { get; set; }
[MaxLength(3)]
public string CE_Category { get; set; }
[MaxLength(10)]
public string Amms { get; set; }
public bool Activities_Agreement { get; set; }
public string Arch_RE { get; set; }
public string Hist_RE { get; set; }
public DateTime? Arch_RE_Date { get; set; }
public DateTime? Hist_RE_Date { get; set; }
public bool? Through_Lanes { get; set; }
public bool? Close_Road { get; set; }
public bool? ROW_Acquisition { get; set; }
public bool? Access_Control { get; set; }
public bool? Fifty_Year_Structure { get; set; }
public bool? Agency_Coordination { get; set; }
public bool? IPAC_Screening_Zone { get; set; }
public bool? Section_404_Permit { get; set; }
public bool? Ground_Disturbance { get; set; }
public bool? Waterway { get; set; }
public bool? Special_Use_Permit { get; set; }
public bool? Floodplain { get; set; }
public string Prepared_By { get; set; }
public string Approved_By { get; set; }
public string Adduser { get; set; }
public DateTime? Date_Added { get; set; }
}
}
Natural_ResourcesContext
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
#nullable disable
namespace EnvApp.Models.DB
{
public partial class Natural_ResourcesContext : DbContext
{
public Natural_ResourcesContext()
{
}
public Natural_ResourcesContext(DbContextOptions<Natural_ResourcesContext> options)
: base(options)
{
}
public virtual DbSet<NR_User> NR_Users { get; set; }
public virtual DbSet<Project_Screen> Project_Screen { get; set; }
public virtual DbSet<TypeOne> TypeOne { get; set; }
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
}
The error is because you are using foreach on the view model itself, not on the properties you want to enumerate.
For Project_Screen and TypeOne, declare them as an enumerable type (eg. Array, List, IEnumerable, etc).
public class MyProjectsViewModel
{
public IEnumerable<Project_Screen> Project_Screen { get; set; }
public IEnumerable<TypeOne> TypeOne { get; set; }
}
You will need to populate those with a collection of values from the controller
var viewModel = new MyProjectsViewModel();
viewModel.Project_Screen = _context.Project_Screen.Where(x => SOME_CONDITION);
viewModel.TypeOne = _context.TypeOne.Where(x => SOME_CONDITION);
In the view you will enumerate those properties (not the model itself).
#foreach (var item in Model.Project_Screen)
and
#foreach (var item in Model.TypeOne)
You were close enough. It seems your Project_Screen and Type_One should be list kind of class from your view iteration we got to know. If so, then your MyProjectsViewModel should be like:
View Model:
public class MyProjectsViewModel
{
public List<Project_Screen> ProjectScreen { get; set; }
public List<Type_One> TypeOne { get; set; }
}
Controller:
public ActionResult ViewModelEnumeration()
{
var proScreen = new List<Project_Screen>()
{
new Project_Screen(){ State_Project_Number = 1,Federal_Project_Number =1,Project_Name = "Project-1", County = "USA"},
new Project_Screen(){ State_Project_Number = 2,Federal_Project_Number =2,Project_Name = "Project-2", County = "CA"},
new Project_Screen(){ State_Project_Number = 3,Federal_Project_Number =3,Project_Name = "Project-3", County = "UK"},
};
var typeOne = new List<Type_One>()
{
new Type_One(){ State_Project_Number = 101,Federal_Project_Number =101,Project_Name = "Type-One-Project-1", County = "USA"},
new Type_One(){ State_Project_Number = 102,Federal_Project_Number =102,Project_Name = "Type-One-Project-2", County = "CA"},
new Type_One(){ State_Project_Number = 103,Federal_Project_Number =103,Project_Name = "Type-One-Project-3", County = "UK"},
};
//Bind to View Model
MyProjectsViewModel viewModel = new MyProjectsViewModel();
viewModel.ProjectScreen = proScreen;
viewModel.TypeOne = typeOne;
return View(viewModel);
}
Note: I am binding demo seeder property into the list. Feel free to change as per your requirement.Just getting you into the point.
View:
#model MVCApps.Models.MyProjectsViewModel
#{
ViewData["Title"] = "ViewModelEnumeration";
}
<h1>My Projects</h1>
<hr />
<h4>Screening Forms</h4>
<table class="table">
<thead>
<tr>
<th>
State Project Number
</th>
<th>
Federal Project Number
</th>
<th>
Project Name
</th>
<th>
County
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.ProjectScreen)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.State_Project_Number)
</td>
<td>
#Html.DisplayFor(modelItem => item.Federal_Project_Number)
</td>
<td>
#Html.DisplayFor(modelItem => item.Project_Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.County)
</td>
</tr>
}
</tbody>
</table>
<br />
<hr />
<h4>Type One Projects</h4>
<table class="table">
<thead>
<tr>
<th>
State Project Number
</th>
<th>
Federal Project Number
</th>
<th>
Project Name
</th>
<th>
County
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.TypeOne)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.State_Project_Number)
</td>
<td>
#Html.DisplayFor(modelItem => item.Federal_Project_Number)
</td>
<td>
#Html.DisplayFor(modelItem => item.Project_Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.County)
</td>
</tr>
}
</tbody>
</table>
Output:
Note: So according to your scenario you can use like this #foreach (var item in Model.Project_Screen). Additionally, be
conscious about your naming convention like Project_Screen Project_Screen is confusing either practice like Project_Screen ProjectScreen or ProjectScreen Project_Screen.
Hope above steps guide you accordingly. You can enhance your Idea more about this on our official document here
Update:
As per your comment I am also adding the example in case of single
object means when you have other than List or IEnumerable
View Model:
public class ProjectsScreenTypeOneViewModel
{
public Project_Screen ProjectScreen { get; set; }
public Type_One TypeOne { get; set; }
}
Controller:
public ActionResult ViewModelFromSingleObject()
{
//Binding Project_Screen Object
var _proScreen = new Project_Screen();
_proScreen.Project_Name = "Test Project-202";
_proScreen.State_Project_Number = 1111;
_proScreen.Federal_Project_Number = 11112021;
_proScreen.County = "USA";
//Binding Type_One Object
var _typeOne = new Type_One();
_typeOne.Project_Name = "Test Type One Project-101";
_typeOne.State_Project_Number = 1010;
_typeOne.Federal_Project_Number = 202121;
_typeOne.County = "UK";
//Binding to view model
var _viewModel = new ProjectsScreenTypeOneViewModel();
_viewModel.ProjectScreen = _proScreen;
_viewModel.TypeOne = _typeOne;
return View(_viewModel);
}
View:
#model MVCApps.Models.ProjectsScreenTypeOneViewModel
#{
ViewData["Title"] = "ViewModelFromSingleObject";
}
<h2>ViewModelFromSingleObject</h2>
<h1>My Projects</h1>
<hr />
<h4>Screening Forms</h4>
<table class="table">
<thead>
<tr>
<th>
State Project Number
</th>
<th>
Federal Project Number
</th>
<th>
Project Name
</th>
<th>
County
</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>
#Html.DisplayFor(modelItem => Model.ProjectScreen.State_Project_Number)
</td>
<td>
#Html.DisplayFor(modelItem => Model.ProjectScreen.Federal_Project_Number)
</td>
<td>
#Html.DisplayFor(modelItem => Model.ProjectScreen.Project_Name)
</td>
<td>
#Html.DisplayFor(modelItem => Model.ProjectScreen.County)
</td>
</tr>
</tbody>
</table>
<br />
<hr />
<h4>Type One Projects</h4>
<table class="table">
<thead>
<tr>
<th>
State Project Number
</th>
<th>
Federal Project Number
</th>
<th>
Project Name
</th>
<th>
County
</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>
#Html.DisplayFor(modelItem => Model.TypeOne.State_Project_Number)
</td>
<td>
#Html.DisplayFor(modelItem => Model.TypeOne.Federal_Project_Number)
</td>
<td>
#Html.DisplayFor(modelItem => Model.TypeOne.Project_Name)
</td>
<td>
#Html.DisplayFor(modelItem => Model.TypeOne.County)
</td>
</tr>
</tbody>
</table>
Output:
Note: Now as you can see I have added both single and List kind of example which will guided you accordingly. If you still
encounter any further issue feel free to share.

Exception when using ASP.NET MVC and Entity Framework

Very new to ASP.NET MVC and Entity Framework.
I'm trying to set up a database with three tables, when I run my code and go to the page "Tickets", I get the following exception:
There is already an open DataReader associated with this Command which must be closed first.
Class 1
public class Ticket
{
[Key]
public int ID { get; set; }
public string Description { get; set; }
[ForeignKey("Practice")]
public int PracticeID { get; set; }
public string Contact { get; set; }
public string Category { get; set; }
//insert Support type using ViewBag (Support type listed in Models.Practices)
[DataType(DataType.DateTime)]
[DisplayFormat(DataFormatString = "{0:dd-MM-yyyy}", ApplyFormatInEditMode = true)]
public DateTime Due { get; set; }
[DataType(DataType.DateTime)]
[DisplayFormat(DataFormatString = "{0:dd-MM-yyyy}", ApplyFormatInEditMode = true)]
public DateTime TimeLogged { get; set; }
[ForeignKey("Consultant")]
public int ConsultantID { get; set; }
public string ConsultantName { get; set; }
public string Status { get; set; }
public virtual Practice Practice { get; set; }
public virtual Consultant Consultant { get; set; }
}
Class 2:
public class Practice
{
[Key]
public int PracticeID { get; set; }
[Display(Name = "Practice Name")]
public string PracName { get; set; }
[Display(Name = "Practice Number")]
public int PracNumber { get; set; }
public string Contact { get; set; }
[Display(Name = "Support Type")]
public string Support { get; set; }
public string Tel { get; set; }
public string Cell { get; set; }
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
public string Address { get; set; }
public virtual List<Ticket> Ticket { get; set; }
}
Class 3:
public class Consultant
{
[Key]
public int ConsultantID { get; set; }
public string Name { get; set; }
[DataType(DataType.Password)]
public string Password { get; set; }
public string Role { get; set; }
public virtual List<Ticket> Ticket { get; set; }
}
I have a search function in my TicketsController:
public ActionResult Index(string searchString, string Consultants)
{
var UserLst = new List<string>();
var UserQry = from d in db.Consultants
orderby d.Name
select d.Name;
UserLst.AddRange(UserQry.Distinct());
ViewBag.User = new SelectList(UserLst);
var tickets = from m in db.Ticket
select m;
if (!String.IsNullOrEmpty(searchString))
{
tickets = tickets.Where(s => s.Description.Contains(searchString));
}
if (!string.IsNullOrEmpty(Consultants))
{
tickets = tickets.Where(x => x.ConsultantName == Consultants);
}
return View(tickets);
}
The error seems to be coming from the HTML code in the INDEX.
#model IEnumerable<MAD.Models.Ticket>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<p>
User: #Html.DropDownList("User", "All")
Description: #Html.TextBox("SearchString") <br />
<input type="submit" value="Search" />
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Consultant.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.Practice.PracName)
</th>
<th>
#Html.DisplayNameFor(model => model.Description)
</th>
<th>
#Html.DisplayNameFor(model => model.Contact)
</th>
<th>
#Html.DisplayNameFor(model => model.Category)
</th>
<th>
#Html.DisplayNameFor(model => model.Due)
</th>
<th>
#Html.DisplayNameFor(model => model.TimeLogged)
</th>
<th>
#Html.DisplayNameFor(model => model.Status)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Consultant.Name)--ERROR CODE
</td>
<td>
#Html.DisplayFor(modelItem => item.Practice.PracName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
<td>
#Html.DisplayFor(modelItem => item.Contact)
</td>
<td>
#Html.DisplayFor(modelItem => item.Category)
</td>
<td>
#Html.DisplayFor(modelItem => item.Due)
</td>
<td>
#Html.DisplayFor(modelItem => item.TimeLogged)
</td>
<td>
#Html.DisplayFor(modelItem => item.Status)
</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>
You have passed in an IQueryable from your controller as your model - called tickets in the controller method. When you start your for each loop on the model, EF starts retrieving results through the connection, but it doesn't actually finish using the connection for this until the end of the loop. The line which is causing the error is trying to access the related Consultant property, which triggers EF to try to load that from the DB, but that causes an exception because you are still in the loop and it is still using the connection to retrieve the tickets query.
The easiest way around this is to force EF to retrieve the results before the loop. I would go for changing the final line in the controller to View (tickets.ToArray) or similar.
I'm not sure, but enabling multiple active result sets might also fix this.

MVC create, edit, delete actions "Cannot implicitly convert type" error

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

ICollection<> inside ICollection<> in Razor - can't retrieve the model names

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

Foreach statement cannot operate on variables of type [Tracker.Models.INV_Assets]?

I'm putting together a fairly simple Code-First MVC5 Inventory Tracking application. I've gotten my app to Seed() and all of my Maintenance tables (Locations, Vendors, Statuses, etc.) I can view/create/edit/delete. I'm now working on the View for my main [INV_Assets] model, but when trying to foreach through the items in my model to display all [INV_Assets] in a table, I get the error: foreach statement cannot operate on variables of type 'Tracker.Models.INV_Assets' because 'Tracker.Models.INV_Assets' does not contain a public definition for 'GetEnumerator'.
Below is the Model for my [INV_Assets]:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using GridMvc.DataAnnotations;
using System.Web.Mvc;
using Tracker.Models;
namespace Tracker.Models
{
[GridTable(PagingEnabled = true, PageSize = 30)]
public class INV_Assets
{
// Setting GridColumn Annotations allows you to use AutoGenerateColumns on view to auto create the Grid based on the model.
public int Id { get; set; }
public int Model_Id { get; set; }
[ForeignKey("Model_Id")]
public virtual INV_Models Model { get; set; }
[Required]
public int Manufacturer_Id { get; set; }
[ForeignKey("Manufacturer_Id")]
public virtual INV_Manufacturers Manufacturer { get; set; }
[Required]
public int Type_Id { get; set; }
[ForeignKey("Type_Id")]
public virtual INV_Types Type { get; set; }
[Required]
public int Location_Id { get; set; }
[ForeignKey("Location_Id")]
public virtual INV_Locations Location { get; set; }
public int Vendor_Id { get; set; }
[ForeignKey("Vendor_Id")]
public virtual INV_Vendors Vendor { get; set; }
[Required]
public int Status_Id { get; set; }
[ForeignKey("Status_Id")]
public virtual INV_Statuses Status { get; set; }
public string ip_address { get; set; }
public string mac_address { get; set; }
public string note { get; set; }
public string owner { get; set; }
public decimal cost { get; set; }
public string po_number { get; set; }
public string description { get; set; }
public int invoice_number{ get; set; }
[Required]
public string serial_number { get; set; }
[Required]
public string asset_tag_number { get; set; }
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")]
public DateTime? acquired_date { get; set; }
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")]
public DateTime? disposed_date { get; set; }
[Required]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")]
public DateTime created_date { get; set; }
[Required]
public string created_by { get; set; }
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")]
public DateTime modified_date { get; set; }
public string modified_by { get; set; }
// Flag to specify if item is available? (Not signed out, not auctioned, recycled, etc.)
//public bool available { get; set; }
}
}
[INV_Assets] View:
#using GridMvc.Html
#model Tracker.Models.INV_Assets
#{
ViewBag.Title = "Home Page";
}
<table style="width:100%;">
#foreach (var item in Model) {
<tr>
<td>#Html.DisplayFor(modelItem => item.Status)</td>
<td>#Html.DisplayFor(modelItem => item.Location)</td>
<td>#Html.DisplayFor(modelItem => item.owner)</td>
<td>#Html.DisplayFor(modelItem => item.Type)</td>
<td>#Html.DisplayFor(modelItem => item.Manufacturer)</td>
<td>#Html.DisplayFor(modelItem => item.Model)</td>
<td>#Html.DisplayFor(modelItem => item.Vendor)</td>
<td>#Html.DisplayFor(modelItem => item.description)</td>
<td>#Html.DisplayFor(modelItem => item.asset_tag_number)</td>
<td>#Html.DisplayFor(modelItem => item.serial_number)</td>
<td>#Html.DisplayFor(modelItem => item.ip_address)</td>
<td>#Html.DisplayFor(modelItem => item.mac_address)</td>
<td>#Html.DisplayFor(modelItem => item.po_number)</td>
<td>#Html.DisplayFor(modelItem => item.invoice_number)</td>
<td>#Html.DisplayFor(modelItem => item.cost)</td>
<td>#Html.DisplayFor(modelItem => item.note)</td>
<td>#Html.DisplayFor(modelItem => item.acquired_date)</td>
<td>#Html.DisplayFor(modelItem => item.disposed_date)</td>
<td>#Html.DisplayFor(modelItem => item.created_date)</td>
<td>#Html.DisplayFor(modelItem => item.created_by)</td>
<td>#Html.DisplayFor(modelItem => item.modified_date)</td>
<td>#Html.DisplayFor(modelItem => item.modified_by)</td>
</tr>
}
</table>
I'm not quite sure how to get around this error and wondered if someone with more experience could weigh-in?
I am getting no issue (not sure why) from my [INV_Locations] Model/View when doing the same:
[INV_Locations]:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Tracker.Models
{
public class INV_Locations
{
public int Id { get; set; }
public string location_dept { get; set; }
public string location_room { get; set; }
[Required]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")]
public DateTime created_date { get; set; }
[Required]
public string created_by { get; set; }
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")]
public DateTime modified_date { get; set; }
public string modified_by { get; set; }
}
}
[INV_Locations] View:
#model IEnumerable<Tracker.Models.INV_Locations>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h3>Maintenance - Locations</h3>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th></th>
<th>
#*#Html.DisplayNameFor(model => model.location_dept)*#
Dept:
</th>
<th>
Room:
</th>
<th>
Created:
</th>
<th>
By:
</th>
<th>
Modified:
</th>
<th>
By:
</th>
</tr>
#foreach (var item in Model) {
<tr>
<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>
<td>
#Html.DisplayFor(modelItem => item.location_dept)
</td>
<td>
#Html.DisplayFor(modelItem => item.location_room)
</td>
<td>
#Html.DisplayFor(modelItem => item.created_date)
</td>
<td>
#Html.DisplayFor(modelItem => item.created_by)
</td>
<td>
#Html.DisplayFor(modelItem => item.modified_date)
</td>
<td>
#Html.DisplayFor(modelItem => item.modified_by)
</td>
</tr>
}
</table>
I tried changing #model Tracker.Models.INV_Assets to #model IEnumerable<Tracker.Models.INV_Assets> on my [INV_Assets] View (just like how my [INV_Locations] View has it. This allows my solution to Build, but when trying to run my application to that View I receive:
System.InvalidOperationException
The model item passed into the dictionary is of type 'Tracker.Models.INV_Assets', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable 1[Tracker.Models.INV_Assets]'.
EDIT - Regarding Shyju's Suggestion:
I changed my HomeController Index() from:
TrackerContext _db = new TrackerContext();
public ActionResult Index(INV_Assets defModel)
{
return View(defModel);
}
to:
TrackerContext _db = new TrackerContext();
public ActionResult Index(INV_Assets defModel)
{
var assetList = new List<Tracker.Models.INV_Assets>();
assetList.Add(defModel);
return View(assetList);
}
While my View now loads, all I get for the Table HTML is:
<table style="width:100%;">
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>0</td>
<td>0.00</td>
<td></td>
<td></td>
<td></td>
<td>01/01/0001</td>
<td></td>
<td>01/01/0001</td>
<td></td>
</tr>
</table>
I've confirmed that my DBContext has 2 complete [INV_Assets] records in it, but they are not showing up in the View? How do I correctly load all the instances of my [INV_Assets] model into the new assetList variable?
EDIT2:
Modified my Index() to:
TrackerContext _db = new TrackerContext();
public ActionResult Index(INV_Assets defModel)
{
var assetList = _db.INV_Assets.ToList(); // EXCEPTION
return View(assetList);
}
but now, while the solution builds, the application fails when I try to run it. Details below:
Error: An exception of type 'System.Data.DataException' occurred in EntityFramework.dll but was not handled in user code. Additional information: An exception occurred while initializing the database. See the InnerException for details.
Message: An exception occurred while initializing the database. See the InnerException for details.
InnerException: {"The underlying provider failed on Open."}
Source: EntityFramework
Your view is bound to a single instance of Tracker.Models.INV_Assets. But inside your view, you are trying to loop through it. You need to make sure what was passed to your view is a collection, so that we can loop through it.
In INV Assets view, change
#model Tracker.Models.INV_Assets
to
#model List<Tracker.Models.INV_Assets>
Also you need to make sure that you are passing a collection of INV_Assets objects from your action method.
public ActionResult INVAssets()
{
var assetList=new List<Tracker.Models.INV_Assets>();
// Ex : manually adding one record. replace with your actual code to load data
// to do : Add item to the list now
assetList.Add(new INV_Assets { Name ="Test"});
return View(assetList);
}
Edit : As per the edit in the question
Your Index action should not be taking an object of INV_Assets as parameter.
TrackerContext _db = new TrackerContext();
public ActionResult Index()
{
var assetList =_db.INV_Assets.ToList();
return View(assetList);
}
Asssuming INV_Assets is a property on your TrackerContext class. If your property name is different, change the above code to reflect that.
If you want to load load the assets for a specific location, update your Index action method to accept the location id as a parameter.
public ActionResult Index(int id)
{
var assetList =_db.INV_Assets.Where(s=>s.Location_Id==id).ToList();
return View(assetList);
}
So your url to access this page would be like
http://yoursitename/YourControllerName/Index/5
where 5 is a valid location id which has some assets associated with it.

Categories

Resources