how to dispaly relational models in one table? - asp.net-mvc

I have three relational models that I want to display in a view in one table. following, I will list 3 models then the controller and the view.
and an error that come out from the controller.
Model Documents
public class Documents
{
[Key]
public int DocId { get; set; }
public string DocName { get; set; }
[ForeignKey("Employee")]
public int EmpId_From { get; set; }
[ForeignKey("Employee")]
public int EmpId_To { get; set; }
[ForeignKey("Organization")]
public int OrganId_From { get; set; }
[ForeignKey("Organization")]
public int OrganId_To { get; set; }
public Employee _Employee { get; set; }
public Organization _Organization { get; set; }
}
Employee
public class Employee
{
[Key]
public int Emp_ID { get; set; }
public string EmpName { get; set; }
}
Organization
public class Organization
{
[Key]
public int OrgID { get; set; }
public string OrgName { get; set; }
}
The Controller
public IActionResult Index()
{
List<Documents> x = _context.Documents.Include(e => e.Employee).Include(o => o.Organization).ToList();
return View(x);
}
The View
#model IEnumerable<Documents>
#foreach (var item in Model.DocumentsList)
{
<tr>
<td>
#item.DocId
</td>
<td>
#item.DocName
</td>
<td> // I can see item.Employee.EmpName but how to display it for this FK EmpId_From & EmpId_To
#item.EmpId_From // item.Employee.EmpName for EmpId_From
</td>
<td>
#item.EmpId_To // item.Employee.EmpName for EmpId_To
</td>
<td>
#item.OrganId_From // item.Organization.OrgName for OrganId_From
</td>
<td>
#item.OrganId_To // item.Organization.OrgName for OrganId_To
</td>
</tr>
}
I get this error from the controller
Microsoft.Data.SqlClient.SqlException: 'Invalid column name '_EmployeeEmp_ID'.
Invalid column name 'OrganizationOrgID'.
Invalid column name 'EmployeeEmp_ID'.
Invalid column name 'OrganizationOrgID'.'

As far as I know, if want to add relationship between the Documents and Employee, Organization, you could directly add the employee and Organization as the property inside the Documents. Then you could directly get the related employee and Organization's value.
Your model class will like this:
public class Documents
{
[Key]
public int DocId { get; set; }
public string DocName { get; set; }
public Employee Emp_From { get; set; }
public Employee Emp_To { get; set; }
public Organization Organ_From { get; set; }
public Organization Organ_To { get; set; }
}
public class Employee
{
[Key]
public int Emp_ID { get; set; }
public string EmpName { get; set; }
}
public class Organization
{
[Key]
public int OrgID { get; set; }
public string OrgName { get; set; }
}
Home controller:
public IActionResult Index()
{
List<Documents> x = _dbContext.Documents.Include(e => e.Emp_From).Include(o => o.Emp_To).Include(o => o.Organ_From).Include(o => o.Organ_To).ToList();
return View(x);
}
View:
<table>
#foreach (var item in Model)
{
<tr>
<td>
#item.DocId
</td>
<td>
#item.DocName
</td>
<td>
#item.Emp_From.EmpName
</td>
<td>
#item.Emp_To.EmpName
</td>
<td>
#item.Organ_From.OrgName
</td>
<td>
#item.Organ_To.OrgName
</td>
</tr>
}
</table>
Result:

Related

UL LI tree, on the client part

How can you build a ul LI tree based on an existing model? On the client side of the application.Nesting can be unlimited
#foreach (var item in Model)
{
<tr>
<th scope="col">#Html.DisplayFor(modelItem => item.Id) </th>
#if (item.ParentId != null)
{
<th scope="col">#Html.DisplayFor(modelItem => item.ParentTitle) </th>
}
else
{
<th scope="col">null </th>
}
<th scope="col">#Html.DisplayFor(modelItem => item.Title) </th>
<th scope="col">#Html.DisplayFor(modelItem => item.Description) </th>
<th scope="col">#Html.DisplayFor(modelItem => item.Created) </th>
</tr>
}
I saw a manual build, just tagging and getting model elements, but is it possible to automate the process somehow?
<ul>
<li>First parent
<ul>
<li>First child
<ul>
Model:
[Table("TestTable", Schema = "dbo")]
public class MyClass
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string Title { get; set; }
public DateTime Created { get; set; }
public string Description { get; set; }
}
public class MySecondClass
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string Title { get; set; }
public DateTime Created { get; set; }
public string Description { get; set; }
public string ParentTitle { get; set; }
}
I would have had a list of children property on your parent rather than 2 very similar classes, then you would be able to make a hierarchical structure:
public class MyClass
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string Title { get; set; }
public DateTime Created { get; set; }
public string Description { get; set; }
public IEnuerable<MyClass> Children { get; set; }
}
Then instead of passing a flat set of classes through as your model, you can build up your hierarchy (in the below, I assumed Model is a list of all your items):
var topLevel = Model.Where(item => !item.HasValue); // or whatever the value is when there is no parent
Then you can loop through this top level to set your children:
foreach (var item in topLevel)
{
item.Children = GetChildren(item.Id, Model);
}
And your Get Children method can be
public static IEnumerable<MyClass> GetChildren(int parentId, IEnumerable<MyClass> allItems)
{
if (parentId.HasValue)
{
var children = allItems.Where(item => item.ParentId.HasValue && item.ParentId.Value.Equals(parentId));
if (children != null && children.Any())
{
foreach (var item in children)
{
item.Children = GetChildren(item.Id, allItems);
}
return children;
}
}
return null;
}
This should help build something then you can have a partial that takes a model of IEnumerable<MyClass> and make it recursive:
#model IEnumerable<MyClass>
#foreach (MyClass item in Model)
{
<ul>
<li>
#item.Title
#if (item.Children != null && item.Children.Any())
{
#Html.Partial("NameOfThisPartial", item.Children)
}
</li>
</ul>
}
And your initial partial call will be:
#Html.Partial("NameOfThisPartial", topLevel)

Different Type of ViewDataDictionary

On an ASP Core project I have a model for Customers:
using System;
using System.Collections.Generic;
namespace RiskDotNet.Models
{
public partial class Customers
{
public Customers()
{
Accounts = new HashSet<Accounts>();
}
public string SrcSys { get; set; }
public string CustId { get; set; }
public string CustNm { get; set; }
public virtual ICollection<Accounts> Accounts { get; set; }
}
}
Thereafter, the accounts pertaining to each customer as:
using System;
using System.Collections.Generic;
namespace RiskDotNet.Models
{
public partial class Accounts
{
public Accounts()
{
Balances = new HashSet<Balances>();
}
public string SrcSys { get; set; }
public string CustId { get; set; }
public string AccId { get; set; }
public string ProdId { get; set; }
public virtual ICollection<Balances> Balances { get; set; }
public virtual Customers Customers { get; set; }
}
}
And third model for the balances (transactions) pertaining to each account:
using System;
using System.ComponentModel.DataAnnotations;
namespace RiskDotNet.Models
{
public partial class Balances
{
[DisplayFormat(DataFormatString = "{0:dd-MMM-yyyy}")]
public DateTime RepDt { get; set; }
public string CustId { get; set; }
public string AccId { get; set; }
public string SrcSys { get; set; }
public decimal? PrOs { get; set; }
public virtual Accounts X { get; set; }
}
}
Now, while I want the Balances table, in the details view of the Accounts page, to be reflected in a sorted manner like a Descending Order of the Reporting Date (RepDt), I am unable to do so.
What is wrong with the following details section of the Accounts Controller:
public async Task<IActionResult> Details(string _SrcSys, string _CustId, string _AccId) //All three join up to form the Composite Key
{
if (_SrcSys == null || _CustId == null || _AccId == null)
{
return NotFound();
}
var Accs = await _context.Accounts
.Include(Cust => Cust.Customers) //To reflect the Customer's Name
.Include(Bal => Bal.Balances) //The Main Portion I want sorted
.SingleOrDefaultAsync(m => m.SrcSys == _SrcSys && m.CustId == _CustId && m.AccId == _AccId);
return View(Accs.Balances.OrderByDescending(x => x.RepDt));
}
Error returns stack:
InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'System.Linq.OrderedEnumerable`2[RiskDotNet.Models.Balances,System.DateTime]', but this ViewDataDictionary instance requires a model item of type 'RiskDotNet.Models.Accounts'.
Follows the View Model:
#model RiskDotNet.Models.Accounts
#{ViewData["Title"] = "Details";}
<div>
<dt><strong>Account:</strong></dt>
<dd>#Html.DisplayFor(model => model.AccId)</dd>
<dt><strong>Src. System:</strong></dt>
<dd>#Html.DisplayFor(model => model.SrcSys)</dd>
<dt><strong>Product:</strong></dt>
<dd>#Html.DisplayFor(model => model.ProdId)</dd>
</dl>
</div>
<div>
<dl>
<dd>
<table class="table">
<tr>
<th>Date</th>
<th style="text-align:right">Pr. O/s.</th>
</tr>
#foreach (var item in Model.Balances)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.RepDt)
</td>
<td style="text-align:right">
#Html.DisplayFor(modelItem => item.PrOs)
</td>
</tr>
}
</table>
</dd>
</dl>
</div>
<a asp-action="Index">Accounts' List</a>

MVC 5 getting Multiple Models into a single view

Newbie to MVC, using MVC 5 and VS 2013.
Code first from existing database, EF6
Goal:
Want to show a listing of all models from the tblModel for an MVP listed in tblMVP
Below is the current state of the project and the runtime error:
Error:
System.Collections.Generic.IEnumerable<WebApplication2.Models.tblAccount>' does not contain a definition for 'tblModels' and no extension method 'tblModels' accepting a first argument of type System.Collections.Generic.IEnumerable<WebApplication2.Models.tblAccount> could be found (are you missing a using directive or an assembly reference?)
Models:
[Table("tblMVP")]
public partial class tblMVP
{
[Key]
public int ID { get; set; }
public int AccountID { get; set; }
public virtual tblAccount tblAccount { get; set; }
}
[Table("tblModel")]
public partial class tblModel
{
[Key]
public int ID { get; set; }
public int AccountID { get; set; }
public virtual tblAccount tblAccount { get; set; }
}
[Table("tblAccount")]
public partial class tblAccount
{
public tblAccount()
{
tblModels = new HashSet();
tblMVPs = new HashSet();
}
public int ID { get; set; }
public virtual ICollection tblModels { get; set; }
public virtual ICollection tblMVPs { get; set; }
}
Controller:
// GET: MVP
public ActionResult Index()
{
var tblAccounts = db.tblAccounts.Include(t => t.tblModels).Include(t => t.tblMVPs);
return View(db.tblAccounts.ToList());
}
View
#model IEnumerable<WebApplication2.Models.tblAccount>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.tblModels.partNumber)
</th>
<th>
#Html.DisplayNameFor(model => model.AccountName)
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.tblModels.partNumber)
</td>
<td>
#Html.DisplayFor(modelItem => item.AccountName)
</td>
</tr>
}
</table>
You're trying to do two different things. You have an IEnumerable<tblAccount>, which doesn't have properties, it just has a list of tblAccount.
So in the top, you're trying to get properties of the IEnumerable, but there aren't any.
In the bottom, you're iterating the IEnumerable, and getting properties of the tblAccount, which you are doing correctly.
So in the top section, you need to get a tblAccount from the IEnumerable so that you can get properties of it. Below is an example of how you can do it.
#model IEnumerable<WebApplication2.Models.tblAccount>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.First().tblModels.partNumber)
</th>
<th>
#Html.DisplayNameFor(model => model.First().AccountName)
</th>
</tr>
Ultimately this is is the bare essentials version of what worked. For better or worse a direct relationship between the tblModel and tblMVP was created and the model loading in the controller was rearranged.
Models:
[Table("tblMVP")]
public partial class tblMVP
{
public tblMVP()
{
tblModels = new HashSet();
}
public int ID { get; set; }
public int AccountID { get; set; }
public string Description { get; set; }
public virtual tblAccount tblAccount { get; set; }
public virtual ICollection tblModels { get; set; }
}
[Table("tblModel")]
public partial class tblModel
{
[Key]
public int ModelID { get; set; }
public int AccountID { get; set; }
[Required]
[StringLength(50)]
public string partNumber { get; set; }
[StringLength(5000)]
public string description { get; set; }
public int? MVPID { get; set; }
public virtual tblMVP tblMVP { get; set; }
}
[Table("tblAccount")]
public partial class tblAccount
{
public tblAccount()
{
tblModels = new HashSet();
tblMVPs = new HashSet();
}
public int ID { get; set; }
[StringLength(150)]
public string AccountName { get; set; }
public int? AccountNumber { get; set; }
public virtual ICollection tblModels { get; set; }
public virtual ICollection tblMVPs { get; set; }
}
**Controller:**
// GET: MVP
public ActionResult Index()
{
var tblModels = db.tblModels.Include(t => t.tblAccount).Include(t => t.tblMVP).ToList();
return View(tblModels.ToList());
}
View
#model IEnumerable<MDLX_Bootstrap_V5.Models.tblModel>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.tblAccount.AccountName)
</th>
<th>
#Html.DisplayNameFor(model => model.partNumber)
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.tblAccount.AccountName)
</td>
<td>
#Html.DisplayFor(modelItem => item.partNumber)
</td>
</tr>
}
</table>

Display UserName and Role in MVC4

I want to create an easy Admin panel for editing users roles. First I want to display users list with their roles.
First I edited some things in AccountModel:
Context:
public class UsersContext : DbContext
{
public UsersContext()
: base("DefaultConnection")
{
}
public DbSet<UserProfile> UserProfiles { get; set; }
public DbSet<UserRole> UserRole { get; set; }
}
User profile:
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public string EmailId { get; set; }
public string Details { get; set; }
public virtual ICollection<UserRole> UserRole { get; set; }
}
User roles:
[Table("webpages_Roles")]
public class UserRole
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int RoleId { get; set; }
public string RoleName { get; set; }
public virtual ICollection<UserProfile> UserProfile { get; set; }
}
After that I created UserController with ActionResult Index:
public ActionResult Index()
{
using (var db = new UsersContext())
{
return View(db.UserProfiles.Include("UserRole").ToList());
}
}
And View:
#model IEnumerable<AnimeWeb.Models.UserProfile>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
User Name
</th>
<th>
User Role
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.UserName)
</td>
<td>
#Html.DisplayFor(modelItem => item.UserRole)
</td>
</tr>
}
Partial View for UserRole looks like this:
#model AnimeWeb.Models.UserRole
<tr>
#Html.DisplayFor(model => model.RoleName),
</tr>
When I try to execute it I get InnerException error: "Invalid object name 'dbo.UserRoleUserProfiles'.". I dont quite get it. Could someone explain me why is this happening and how to resolve this?
Seems like the problem lies here
public virtual ICollection<UserRole> UserRole { get; set; }
And you don't have a mapping for these classes, so the default setting creates a UserRoleUserProfiles table(or class) and it doesn't exist in the database, so the problem occurs.
You can try remove this line of code and then try run the project again

mvc model validation required not working on all fields

I'm working in ASP.NET MVC 4 and I have the problem that my model validation isn't working correctly. For some reason not all my required fields have to be filled in.
Here's my model:
public class MovieModel
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
public DateTime ReleaseDate { get; set; }
[Required]
public string Genre { get; set; }
[Required]
public decimal Price { get; set; }
public virtual ICollection<RoleInMovie> RoleInMovie { get; set; }
}
Here's the View:
#using (Html.BeginForm())
{
<table>
<tr>
<td>
<label>Name:</label></td>
<td>#Html.EditorFor(m => m.Name)</td>
<td>#Html.ValidationMessageFor(m => m.Name)</td>
</tr>
<tr>
<td>
<label>Genre:</label></td>
<td>#Html.EditorFor(m => m.Genre)</td>
<td>#Html.ValidationMessageFor(m => m.Genre)</td>
</tr>
<tr>
<td>
<label>Price:</label></td>
<td>#Html.EditorFor(m => m.Price)</td>
<td>#Html.ValidationMessageFor(m => m.Price)</td>
</tr>
</table>
<button type="submit">Submit</button>
}
And here's my action:
[HttpPost]
public ActionResult Add(MovieModel model)
{
if(ModelState.IsValid)
{
return RedirectToAction("Index");
}
return View();
}
Now here's the thing: as soon as I enter only a price, modelstate.isvalid becomes true. When hovering over my model, it sais both name and genre are null. Ofcourse they are required, but the validation doesn't work.
Also, the validationmessagefor only works on price.
I hope I'm not overlooking something too ridiculous. Thanks for the help!
Return the invalid model back to the view:
[HttpPost]
public ActionResult Add(MovieModel model)
{
if(ModelState.IsValid)
{
return RedirectToAction("Index");
}
return View(model); // <----
}
Oh, and make sure that the required attribute is disallowing empty strings
http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.requiredattribute.allowemptystrings.aspx
public class MovieModel
{
public int Id { get; set; }
[Required(AllowEmptyStrings = false)]
public string Name { get; set; }
public DateTime ReleaseDate { get; set; }
[Required(AllowEmptyStrings = false)]
public string Genre { get; set; }
[Required]
public decimal Price { get; set; }
public virtual ICollection<RoleInMovie> RoleInMovie { get; set; }
}

Resources