MVC4 Foreign Key property is null - c#

I have an Expenses and Categories tables. I have seeded the tables with few entries, but when pulled from DB the Category property is null. I would expect it to be automatically populated with entries from Category table. What am I missing?
Model:
public class Expense
{
public int ExpenseId { get; set; }
[DataType(DataType.Currency)]
public decimal Amount { get; set; }
[ForeignKey("CategoryId")]
public Category Category { get; set; }
[Required(ErrorMessage = "You must select some category!")]
public int CategoryId { get; set; }
}
public class Category
{
public int CategoryId { get; set; }
public string Description { get; set; }
public virtual ICollection<Expense> Expenses { get; set; }
}
View:
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Amount)
</td>
<td>
#item.CategoryId
</td>
<td>
#item.Category.Description //NullReferenceException here
</td>
</tr>
Controller:
// GET: Expenses
public ActionResult Index()
{
return View(db.Expenses.ToList());
}

Try marking the Category property as virtual. Navigation properties need to be virtual to support the lazy loading if it is not eager loaded.

Related

How do you reference a foreign key from a razor view page?

New to .net core here and I am going through razor tutorials and trying to add my own things to it. I have two tables: Order and Stock. I can list all Orders or all stocks, but when I want to list all Orders, I want to display the stock name (not the stockID) in the view page (near end of code). How do you reference the foreign key 'stockID' from the view page? Here is my code:
public class OrderModel
{
public int Id { get; set; }
public string OrderName { get; set; }
public DateTime OrderDate { get; set; } = DateTime.UtcNow;
public int Quantity { get; set; }
public decimal StockUnitCost { get; set; }
public decimal StockTotalCost { get; set; }
public decimal WinLoseAmt { get; set; }
public int StockId { get; set; }
}
public class StockModel
{
public int Id { get; set; }
public string StockName { get; set; }
public string StockTicker { get; set; }
public string StockType { get; set; }
public string Sector { get; set; }
}
public class OrderDisplayModel : PageModel
{
private readonly IOrderData _orderData;
private readonly IStockData _stockData;
public OrderModel Order { get; set; }
public List<OrderModel> orderList { get; set; }
public OrderDisplayModel(IOrderData orderData, IStockData stockData)
{
_orderData = orderData;
_stockData = stockData;
}
public async Task OnGet()
{
orderList = await _orderData.GetOrder();
}
}
<h1>My Orders</h1>
<table class="'table table-striped">
<thead class="thead-dark">
<tr>
<th>Order Name</th>
<th>Stock</th>
<th>Quantity</th>
<th>Cost Basis</th>
<th>Total Cost</th>
<th>Open Mkt Gain</th>
<th>Order Date</th>
</tr>
</thead>
<tbody>
#foreach (var order in Model.orderList)
{
<tr>
<td>#order.OrderName</td>
<td>#Model.StockPurchased</td>
<td>#order.StockId</td>
<td>#order.Quantity</td>
<td>#order.StockUnitCost</td>
<td>#order.StockTotalCost</td>
<td>#order.WinLoseAmt</td>
<td>#order.OrderDate</td>
</tr>
}
</tbody>
</table>
Thanks!
Create a virtual property and make it ForeignKey (and InverseProperty if you want to have another virtual collection property from Stock to Orders).
Something like this
....
public int StockId { get; set; }
[ForeignKey(nameof(StockId))]
[InverseProperty("Orders")]
public virtual Stock Stock { get; set; }
Then, you can either .Include(s=>s.Stock) in you context call and access it like order.Stock.StockName. Or setup Lazy loading (which requires a a bit more work in recent .NET core versions) and you access it without needing to Inclue it.

Asp.Net Core EF Core Table Joins

I have two Objects, let says Employee and Address as follows
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public int DepartmentId {get; set; }
}
public class Department
{
public int Id { get; set; }
public string Name { get; set; }
}
The relationship model is that each employee belongs to a single department (using DepartmentID property)
I want to create a view which shows all employees and instead of displaying the department ID, the department name is shown instead
My controller looks like this
public class EmployeeController : Controller
{
private readonly IAppRepository _appRepository;
public EmployeeController(IAppRepository appRepository)
{
_appRepository = appRepository;
}
public ViewResult List
{
Department department;
// retrieve all employee from DBContext (SQL Server)
var model = _appRepository.GetEmployees;
// retrieve department details
department = _appRepository.GetDepartment(model.DepartmentId);
ViewBag.department = department;
}
}
My problem seems to be with the last two lines (//retrieve department details. as model is returning an enumerable of employee.
How can this be achieved, I was thinking using ViewModel but have not found a way yet. thanks
In my opinion, you could configure relationships between Employee and Department,refer to here
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public int DepartmentId { get; set; }
[ForeignKey("DepartmentId")]
public Department Department { get; set; }
}
public class Department
{
public int Id { get; set; }
public string Name { get; set; }
}
In your repository GetEmployees, you could get all employees with their own Department using Include, refer to here
var employees = _context.Employees.Include(e => e.Department).ToList();
Then your model of var model = _appRepository.GetEmployees; will contains Department info for each employee and you could achieve name in view,for example
#model IEnumerable<Employee>
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.Department)
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Department.Name)
</td>
</tr>
}
</tbody>
</table>

Listing all Items under a Category C# MVC

I would like some direction on how to be able to list all the items under a certain category in a view. I have already searched around and can't find anything, If someone know of any other posts or articles please point me there. Other wise here is my model...
public class Category
{
[Key]
public int ID { get; set; }
[Display(Name = "Category")]
public string Name { get; set; }
public virtual ICollection<MenuItem> MenuItem { get; set; }
}
public class MenuItem
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
[DataType(DataType.MultilineText)]
public string Description { get; set; }
public string Image { get; set; }
public int CategoryID { get; set; }
public virtual Category Category { get; set; }
}
Thanks for any help anyone can provide.
assuming your category is set at the model
#foreach(var item in Model.MenuItem)
{
#Html.HiddenFor(x => item.ID)
<div>#Html.DisplayFor(x => item.Name)</div>
// carry on with other properties / markup
}
Say you want to loop over the MenuItem property in the Category model, in your view you'd have something like this:
At the top of the View, you'd have this:
#model Category
#foreach (var item in Model.MenuItem)
{
<tr id="menu-item">
<td>#id</td>
<td>#Name</td>
<td>#Description</td>
<td>#Image</td>
</tr>
}
#foreach (var item in Model.MenuItem)
{
<tr>
<td>#Name</td>
<td>#Description</td>
</tr>
{

How to show other model column in Razor view?

Currently i'm able to show all column in razer view from userRole model.
Just curious if i like to show the SiteName column in UserRole Razor view, instead of showing SiteID, is it possible? I know it can be done via custom view model, but is it a must? Please correct me if i'm wrong!
UserRole Model:
public int UserID { get; set; }
public string UserName { get; set; }
public int SiteID { get; set; }
*No SiteName column here....so i only can show SiteID in razor..
Site Model :
public int SiteID { get; set; }
public string SiteName { get; set; } <<-- the column i want..
Controller:
public ActionResult Index()
{
//need join table here perhaps?
return View(db.User_Role.ToList());
}
Razor View:
#model IEnumerable<FAB_Portal_POC.Models.UserRole>
<table class="table table-striped table-hover">
<tr>
<th>
#Html.DisplayNameFor(model => model.UserName)
</th>
<th>
#Html.DisplayNameFor(model => model.Role)
</th>
<th>
#Html.DisplayNameFor(model => model.SiteID)
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.UserName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Role)
</td>
<td>
#Html.DisplayFor(modelItem => item.SiteID) <<-- i want site name.
</td>
</tr>
}
</table>
The first problem is that your UserRole entity model doesn't seem to have a navigation property.
You don't need to, but then querying becomes awkward:
var rolesWithSite = from r in db.User_Role
join s in db.Sites on s.ID equals r.Site_ID
select new
{
Role = r,
Site = s
}
.ToList();
While when you add a navigation property (perhaps even instead of the foreign key property):
public class User_Role
{
public int UserID { get; set; }
public string Role { get; set; }
public string UserName { get; set; }
public virtual Site Site { get; set; }
}
Querying will become a whole lot easier:
var rolesWithSite = db.User_Role.Include(r => r.Site).ToList();
You can then introduce a viewmodel:
public class UserRoleViewModel
{
public int UserID { get; set; }
public string UserName { get; set; }
public string Role { get; set; }
public string Site { get; set; }
}
And map the query results to that:
var viewModels = rolesWithSite.Select(r => new UserRoleViewModel
{
UserID = r.UserID,
UserName = r.UserName,
Role = r.Role,
Site = r.Site.SiteName,
}).ToList();
return View(viewModels);
Entities and Models are very different.
You have to create a specific model for your page.
something like this :
PageModel
public string UserName { get; set; }
public string SiteName { get; set; }
In your controller your have to prepare all the data you want to send to the page. It s here that you will "associate" your entities to your pagemodel
public ActionResult Index()
{
var roles = db.User_Role.ToList();
var sites = db.Sites.ToList(); // i don t know how you get this information in your exemple.
//define here every property of the PageModel you want to use there
var model = new PageModel();
model.UserName = roles.UserName;
model.SiteName = sites.Select(...).SiteName;
return View(model);
}
then in razor view
#model IEnumerable<FAB_Portal_POC.Models.PageModel>
Hope it will help
You have multiple ways to do that the simple one is you have to create new class name UserRoleViewData and mention these fields and pass the class object to view. just like that.
New Class UserRoleViewData Look like this
public int UserID { get; set; }
public string UserName { get; set; }
public int SiteID { get; set; }
public string SiteName { get; set; }
and your Controller
public ActionResult Index()
{
List<className> dto = (from a in _db.User_Role
join b in db.Site on a.SiteID equals b.SiteID
select (new classname { UserID =a.UserID , UserName =a.UserName , SiteID =a.SiteID , SiteName =b.SiteName })).ToList();
return View(dto);
}
In View You have to change #model IEnumerable<FAB_Portal_POC.folderName.ClassName>
and map other property on view like others.I hope u'll understand and this will help you.
You can store the sites list in the ViewBag and show the site name by extracting it from the ViewBag:
public ActionResult Index()
{
ViewBag.Sites = db.Sites.ToList();
return View(db.User_Role.ToList());
}
And the View:
<td>
#Html.DisplayFor(modelItem => ViewBag.Sites.Single(s => s.SiteID == item.SiteID).SiteName)
</td>
Another, and to me a better approach, would be to create a ViewModel for your view which contains all of the data that you need. And return that view model to your view.
public class UserSiteViewModel
{
public int UserID { get; set; }
public string UserName { get; set; }
public string Role { get; set; }
public int SiteID { get; set; }
public string SiteName { get; set; }
}
No need to use ViewBag , join between 2 tables and store result in another viewModel it's vary bad idea. Please check out reference link, It will really help you to do Code in Very good direction. Click Here

C# reflection use variable as object.[var]

I'm trying to generate a table in a razor view using reflection to pull the properties from the model.
Here is what I've tried:
#if (#Model.Count() > 0)
{
System.Reflection.PropertyInfo[] properties = Model.First().GetType().GetProperties();
<table>
<thead>
<tr>
#foreach (var property in properties)
{
if (char.IsLower(property.Name.ToCharArray()[0])) //ignore foreign keys
{
continue;
}
<th>#property.Name</th>
}
</tr>
</thead>
<tbody>
#foreach (PCNWeb.Models.Switch item in Model)
{
/*System.Reflection.PropertyInfo[]*/ properties = item.GetType().GetProperties();
<tr>
#foreach (var property in properties)
{
<td>
#Html.DisplayFor(modelItem => item.[property.Name])
</td>
}
</tr>
}
</tbody>
</table>
}
Let me point out the part of the code that I'm not sure what to do with:
<td>
#Html.DisplayFor(modelItem => item.[property.Name])
</td>
The property.Name contains the name of the property of item that I want to access.
If I were to hand write the innermost td one example would be:
<td>
#Html.DisplayFor(modelItem => item.Switch_Location)
</td>
where "Switch_Location" is the value of property.Name
So basically I need to access the value of a property of item based on the name of the property stored in a variable.
EDIT adding model:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace PCNWeb.Models
{
public partial class Switch
{
public Switch()
{
this.Ports = new List<Port>();
this.Switch_Location = new Switch_Location();
this.Switch_Model = new Switch_Model();
this.UPS = new UPS();
}
[Key]
public int switchRecId { get; set; }
[Required]
public int locationRecId { get; set; }
[Required]
public int modelRecId { get; set; }
//public int gatewayRecId { get; set; }
[Required]
public int upsRecId { get; set; }
[Required]
public int Number { get; set; }
[Required]
[StringLength(64)]
public string Name { get; set; }
[StringLength(80)]
public string Description { get; set; }
[StringLength(32)]
public string Cabinet { get; set; }
[StringLength(40)]
public string Power_Feed { get; set; }
[Required]
public Nullable<int> ipOctet1 { get; set; }
[Required]
public Nullable<int> ipOctet2 { get; set; }
[Required]
public Nullable<int> ipOctet3 { get; set; }
[Required]
public Nullable<int> ipOctet4 { get; set; }
public virtual ICollection<Port> Ports { get; set; }
public virtual Switch_Location Switch_Location { get; set; }
public virtual Switch_Model Switch_Model { get; set; }
public virtual UPS UPS { get; set; }
}
}
So basically I need to access the value of a property of item based on the name of the property stored in a variable.
No, you need to access the value of a property based on a PropertyInfo object describing it. That's far far easier.
property.GetValue(item)
If you dont really need the DisplayFor method, you can do it like this in your loop:
<tbody>
#foreach (PCNWeb.Models.Switch item in Model)
{
/*System.Reflection.PropertyInfo[]*/ properties = item.GetType().GetProperties();
<tr>
#foreach (var property in properties)
{
<td>
#property.GetValue(item,null)
</td>
}
</tr>
}
</tbody>

Categories

Resources