Different Type of ViewDataDictionary - asp.net-mvc

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>

Related

how to dispaly relational models in one table?

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:

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)

How to bind one model for creating dropdownlist and second model for textboxes using strongly typed view in MVC?

1st model:
public class VehicleMake
{
[Key]
public int MakeId { get; set; }
public string Make { get; set; }
}
2nd Model:
public class VehicleModel
{
[Key]
public int ModelId { get; set; }
public string Model { get; set; }
public DateTime Year { get; set; }
public int MakeId { get; set; }
public VehicleMake VehcileMake { get; set; }
}
How to pass two models as strongly typed view.
my view has 1) one dropdownlist which bind make and makeid from VehicleMake class
2) one textbox as Model which binds from vehicleModle class
Please suggest how to create a view using multiple models?
#model MvcApplication1.Data.ViewVMModel
....
<h2>CreateModel</h2>
<table>
<tr>
<td>#Html.Label("Select Make")</td>
<td>#Html.DropDownListFor(model=>model.VehicleMake,new SelectList(Model. "MakeId","Make")))</td>
</tr>
<tr>
<td>Enter Model </td>
<td>#Html.TextBoxFor(model=>model.VehcileModel)</td>
</tr>
</table>
You're editing data so first step is to create a view model (add other validation attributes as required).
public class VehicleVM
{
[Required(ErrorMessage = "...")]
public string Model { get; set; }
[Required(ErrorMessage = "...")]
public DateTime? Year { get; set; } // make nullable to protect against under-posting attacks
[Required(ErrorMessage = "...")]
[Display(Name = "Make")]
public int? SelectedMake { get; set; }
public IEnumerable<SelectListItem? MakesList { get; set; }
}
and in the GET method, initialize an instance of your view model, populate it and pass it to the view
var makes = db.VehicleMakes; // get the Makes from the database
VehicleVM vehicle = new VehicleVM()
{
MakesList = new SelectList(makes, "MakeId", "Make")
};
return View(vehicle);
and in the view
#model VehicleVM
....
#using (Html.BeginForm())
{
#Html.LabelFor(m => m.SelectedMake)
#Html.DropDownListFor(m => m.SelectedMake, Model.MakesList)
#Html.ValidationMessageFor(m => m.SelectedMake)
#Html.LabelFor(m => m.Model)
#Html.TextBoxFor(m => m.Model)
#Html.ValidationMessageFor(m => m.Model)
....
Which will post back to
public ActionResult Create(VehicleVM vehicle)
your Viewmodel should be something like this
public VehicleModel VehicleModel { get; set; }
public List<VehicleMake> VehcileMakeList { get; set; }
and in your view
#model MvcApplication1.Data.ViewVMModel
....
<h2>CreateModel</h2>
<table>
<tr>
<td>#Html.Label("Select Make")</td>
<td>#Html.DropDownListFor(model=>model.VehicleModel.MakeId ,new SelectList(Model.VehcileMakeList, "MakeId","Make")))</td>
</tr>
<tr>
<td>Enter Model </td>
<td>#Html.TextBoxFor(model=>model.VehcileModel.Model)</td>
<td>#Html.TextBoxFor(model=>model.VehcileModel.Year )</td>
</tr>
</table>
and in your action
ViewVMModel vm = new ViewVMModel();
vm.VehcileMakeList = //get list of make
vm.VehicleModel = new VehicleModel();
return view(vm);

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