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>
Related
There are 2 models. The user is logging into the system. I want a value from the current model to be added to the logged in user's table when he clicks the button in the Forum View. Ogrenci Model enters the system. When the button is clicked, I want ProjectName to be added to the BekleyenProje column in the Ogrenci Model. How can I do that?
Model 1:
public class Ogrenci
{
public int OgrenciID { get; set; }
public int OgrenciNumarasi { get; set; }
public string Ad { get; set; }
public string Soyad { get; set; }
public string Bolum { get; set; }
public short Sinif { get; set; }
public string Yetenekler { get; set; }
public string Sifre { get; set; }
public string BekleyenProje { get; set; }
public string OnaylananProje { get; set; }
//FK
public List<Proje> Projeler { get; set; }
}
Model 2:
public class Proje
{
public int ProjeID { get; set; }
public string ProjeAdi { get; set; }
public string Aciklama { get; set; }
public DateTime EklenmeTarihi { get; set; }
//FK
public int OgrenciID { get; set; }
public Ogrenci Ogrenci { get; set; }
}
ForumController:
public class ForumController : Controller
{
private OgrenciContext db = new OgrenciContext();
// GET: Forum
public ActionResult Index()
{
//Include(o => o.Ogrenci) -- öğrenci bilgilerini dahil ediyoruz
return View(db.Projeler.Include(o => o.Ogrenci).ToList());
}
}
Forum Index View (The button I'm talking about is here):
#model IEnumerable<DonemProjesi.Models.Proje>
#{
ViewBag.Title = "Index";
}
<table class="table table-striped table-bordered table-hover table-condensed cols-3 custom_table">
<thead>
<tr>
<th scope="col">Proje</th>
<th scope="col">Etkileşimler</th>
<th scope="col">Yayınlanma Tarihi</th>
<th scope="col">Detay</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
<div>#Html.DisplayFor(modelItem => item.ProjeAdi)</div>
<small>#Html.DisplayFor(modelItem => item.Ogrenci.Ad)</small>
</td>
<td>
<ul class="activity_outer">
<li><strong>03</strong><span>Başvuranlar</span></li>
<li><strong>01</strong><span>Dahil olanlar</span></li>
</ul>
</td>
<td>
<div class="last_activity"><span class="time_ago">#Html.DisplayFor(modelItem => item.EklenmeTarihi)</span></div>
</td>
<td>
<button type="button" class="login-button">#Html.ActionLink("Proje Detayı", "Details", "Proje", new { id = item.ProjeID }, new { #class = "detayy" })</button>
<button type="button" class="login-button"></button> //BUTTON IS HERE
</td>
</tr>
}
</tbody>
Also, Controller for Login:
public class SecurityController : Controller
{
OgrenciContext db = new OgrenciContext();
// GET: Security
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(Ogrenci ogrenci)
{
var kullanici = db.Ogrenciler.FirstOrDefault(x=>x.OgrenciNumarasi == ogrenci.OgrenciNumarasi && x.Sifre == ogrenci.Sifre);
if (kullanici!=null)
{
FormsAuthentication.SetAuthCookie(kullanici.Ad, false);
Session.Add("OgrenciID", kullanici.OgrenciID); //kimlik doğrulamasu yapılan kullanıcının ID'si alınıyor
return RedirectToAction("Details","Ogrenci", new {#id=kullanici.OgrenciID });
}
else
{
ViewBag.Mesaj = "Geçersiz numara veya şifre girdiniz!";
return View();
}
}
}
It's better to use repository pattern, but a direct solution would be:
kullanici.BekleyenProje = Request["ProjectName"];
db.SaveChanges();
Also it depends on how many properties you want to pass. If it's only one, you can send it in the Request. Otherwise, you create a view model with the necessary members.
Make sure the button is submitting the form and ProjectName is a hidden field inside the form.
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.
As of right now, I have a table on my view that looks like so:
The purpose of this table is to show a count of how many occurrences happened at each location (on the left) during the current week.
I have 3 tables in my database that I am using to create this table.
Table One
public partial class code_WeighLocation
{
public code_WeighLocation()
{
tbl_WeighAssc = new HashSet<tbl_WeighAssc>();
}
public int ID { get; set; }
[Required]
[StringLength(50)]
public string Weigh_Location { get; set; }
public bool Active { get; set; }
public virtual ICollection<tbl_WeighAssc> tbl_WeighAssc { get; set; }
}
Table Two - Association Table
public partial class tbl_WeighAssc
{
public int Id { get; set; }
public int WeighLocationId { get; set; }
public int TEUId { get; set; }
public int OccurenceCount { get; set; }
public virtual code_WeighLocation code_WeighLocation { get; set; }
public virtual tbl_TEUForm tbl_TEUForm { get; set; }
}
Table Three
public partial class tbl_TEUForm
{
public tbl_TEUForm()
{
tbl_TEUArrestAssc = new HashSet<tbl_TEUArrestAssc>();
tbl_WeighAssc = new HashSet<tbl_WeighAssc>();
tblTEUInspectionAsscs = new HashSet<tblTEUInspectionAssc>();
}
public int Id { get; set; }
public string PersonnelIBM { get; set; }
[Column(TypeName = "date")]
public DateTime EventDate { get; set; }
public bool Active { get; set; }
public virtual ICollection<tbl_TEUArrestAssc> tbl_TEUArrestAssc { get; set; }
public virtual tblPersonnel tblPersonnel { get; set; }
public virtual ICollection<tbl_WeighAssc> tbl_WeighAssc { get; set; }
public virtual ICollection<tblTEUInspectionAssc> tblTEUInspectionAsscs { get; set; }
}
Now, my view is taking in a viewmodel:
ViewModel
public class PersonnelDetailsVm
{
private static ConnectionStringName db = new ConnectionStringName();
public PersonnelDetailsVm()
{
CurrentWeekDates = new List<DateTime>();
}
public string IBM { get; set; }
[Display(Name = "Name")]
public string UserName { get; set; }
[Display(Name = "TEU OT Rate")]
public string Teu_OT_Rate { get; set; }
[Display(Name = "MCSAP OT Rate")]
public string Mcsap_OT_Rate { get; set; }
[StringLength(10)]
public string Division { get; set; }
public bool Active { get; set; }
public List<DateTime> CurrentWeekDates { get; set; }
public List<tbl_WeighAssc> WeighAssociations { get; set; }
public List<code_WeighLocation> WeighLocations => db.code_WeighLocation.ToList();
}
In my view to create the table that I am showing above, my code looks like this:
<table class="table table-bordered table-hover mt-3">
<thead>
<tr>
<th></th>
#foreach (var date in Model.CurrentWeekDates)
{
<th>#date.ToString("ddd") <br /> #date.ToShortDateString()</th>
}
</tr>
</thead>
<tbody>
#foreach (var weighLocation in Model.WeighLocations)
{
<tr>
<td>#weighLocation.Weigh_Location</td>
</tr>
}
</tbody>
</table>
Now, in my database, in the association table I only have 2 records, and both records were entered on Friday, 9/7/2018. One record is for WIMS/SR-1 with an occurence count of 2. The other is for FIXED/Blackbird with an occurence count for 2. So, my goal is to show those counts under Fri 9/7/2018 in their respective rows/cells and every other cell be filled with a 0 because there aren't any other records in the association table for those locations during this current week.
Here is my controller code to show how I'm populating the days of the week and getting the correct records based off of those dates.
var startOfWeek = DateTime.Today.AddDays((int) CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek -
(int) DateTime.Today.DayOfWeek);
person.CurrentWeekDates = Enumerable.Range(0, 7).Select(i => startOfWeek.AddDays(i)).ToList();
var teuFormIds = db.tbl_TEUForm
.Where(x => person.CurrentWeekDates.Contains(x.EventDate) && x.PersonnelIBM == person.IBM).Select(t => t.Id).ToList();
person.WeighAssociations = db.tbl_WeighAssc.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
Any help is appreciated
I am not sure if I get this right, but I guess what you need is this,
for each time you are looping your locations, you should loop your dates again, and then do count or sum occurencecount (depending on your system design I didn't get it) and display it.
You don't need to worry about the cell order because you are looping the same days always so they will align first col is always the first day and so on.
also please double check the conditions I used, I am not sure if it is correct, but anyway this is the approach.
<!-- Loop through locations -->
#foreach (var weighLocation in Model.WeighLocations)
{
<tr>
<td>#weighLocation.Weigh_Location</td>
<!-- loop through current days week days for each location-->
#foreach(var currentDay in Model.CurrentWeekDates)
{
<!-- Here you count the rows or maybe sum the OccurenceCount I am not sure how you design it, I used count but you can use sum OccurenceCount -->
<td>
<!-- Compare the location id and the teuForm date -->
#Model.WeighAssociations.Where(e => e.WeighLocationId == weighLocation.Id && e.tbl_TEUForm.EventDate == currentDay).Count()
</td>
}
</tr>
}
I have figured this out.
In my view I edited the table tbody code to this:
<tbody>
#foreach (var weighLocation in Model.WeighLocations)
{
<tr>
<td>#weighLocation.Weigh_Location</td>
#foreach (var date in Model.CurrentWeekDates)
{
if (Model.WeighAssociations.Any(x => x.tbl_TEUForm.EventDate == date && x.WeighLocationId == weighLocation.ID))
{
<td>#Model.WeighAssociations.Single(x => x.tbl_TEUForm.EventDate == date && x.WeighLocationId == weighLocation.ID).OccurenceCount</td>
}
else
{
<td>0</td>
}
}
</tr>
}
</tbody>
HTML.BeginCollectionItem does not return values to the controller. It always return NULL in the controller. I am not sure if has got anything to do if there is a partial view within another partial view. Below is the snippet of the code/view.
ProductEditModel
public class ProductEditModel
{
// Product details displayed on edit form
public Product ProductModel { get; set; }
public IList<ProductAssetAudioEditModel> ProductAssetAudios { get; set;}
}
ProductAssetAudioEditModel
public class ProductAssetAudioEditModel
{
public int ProductId { get; set; }
public int? ProductAssetId { get; set; }
public virtual IList<ProductAssetResourceEditModel> ProductAssetResources { get; set; }
}
ProductAssetResourceEditModel
public class ProductAssetResourceEditModel
{
public int? ProductAssetResourceId { get; set; }
public int ProductAssetId { get; set; }
public int ResourceNumber { get; set; }
public int? ElectronicFileId { get; set; }
public ElectronicFile ElectronicFile { get; set; }
}
ProductEditView.cshtml
<div id="audio">
#foreach (ProductAssetAudioEditModel audio in Model.ProductAssetAudios)
{
Html.RenderPartial("_ProductAssetAudioRow", audio);
}
</div>
_ProductAssetAudioRow.cshtml
#using (Html.BeginCollectionItem("ProductAssetAudios"))
{
....
<tbody>
#foreach (var resource in Model.ProductAssetResources)
{
Html.RenderPartial("_ProductAssetAudioResource", resource);
}
</tbody>
.....
}
_ProductAssetAudioResource
#using (Html.BeginCollectionItem("ProductAssetResources"))
{
#Html.HiddenFor(m => Model.ProductAssetResourceId)
#Html.HiddenFor(m => Model.ProductAssetId)
<td>
#if (Model.ElectronicFileId.HasValue)
{
#Html.HiddenFor(model => model.ElectronicFileId)
#Html.ActionLink(Model.ElectronicFile.FileName, "Details", "File", new { id = Model.ElectronicFileId, area = "Edi" }, null);
}
</td>
<td>
#Html.EditorFor(c => Model.TrackTitle)
</td>
}
In the controller , ProductAssetResources is NULL even though edit page binds the properties correctly for editing.
I am not sure what I am missing here.
-Alan-
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.