Join table in Entity Framework and display other column - asp.net-mvc

I'm trying to make my list to show data from another column instead of its ID, currently they are showing like so:
This is what I work out so far:
Controller:
public class CompanyAdmin
{
public string Id { get; set; }
[Required(AllowEmptyStrings = false)]
[Display(Name = "Company Name")]
public string CompanyName { get; set; }
public virtual List<Certificate> Certificates { get; set; }
public class Certificate
{
[Key]
[Display(Name = "Certificate No.")]
public string CertNo { get; set; }
[Display(Name = "Company")]
public IEnumerable<SelectListItem> Companies { get; set; }
[Required]
public string Company { get; set; }
[Display(Name = "User")]
public IEnumerable<SelectListItem> UserList { get; set; }
[Required]
public string User { get; set; }
public string UploadedBy { get; set; }
[Display(Name = "Description")]
public string CertDescription { get; set; }
[Display(Name = "File Location")]
public string CertFileLocation { get; set; }
[Display(Name = "Last Modified")]
public DateTime LastModifiedDate { get; set; }
}
public class CertificateViewModel
{
[Display(Name = "Certificate No.")]
public string CertNo { get; set; }
public string User { get; set; }
[Display(Name = "User")]
public string UserName { get; set; }
public string Company { get; set; }
[Display(Name = "Company")]
public string CompanyName { get; set; }
[Display(Name = "Description")]
public string CertDescription { get; set; }
[Display(Name = "Last Modified")]
public DateTime LastModifiedDate { get; set; }
}
Here is my controller:
public ActionResult Index()
{
if (User.IsInRole("Admin"))
{
IEnumerable<CertificateViewModel> model = null;
model = (from c in db.CertificateDB
join u in db.Users on c.User equals u.Id
join d in db.CompanyDB on c.Company equals d.Id
select new CertificateViewModel
{
CertNo = c.CertNo,
UserName = u.UserName,
CompanyName = d.CompanyName,
CertDescription = c.CertDescription,
LastModifiedDate = c.LastModifiedDate
}
);
return View(model);
}
else
{
return RedirectToAction("Index", "Home");
}
}
and the view:
#model IEnumerable<IdentitySample.Models.CertificateViewModel>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.CertNo)
</th>
<th>
#Html.DisplayNameFor(model => model.Company)
</th>
<th>
#Html.DisplayNameFor(model => model.User)
</th>
<th>
#Html.DisplayNameFor(model => model.CertDescription)
</th>
<th>
#Html.DisplayNameFor(model => model.LastModifiedDate)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.CertNo)
</td>
<td>
#Html.DisplayFor(modelItem => item.Company)
</td>
<td>
#Html.DisplayFor(modelItem => item.User)
</td>
<td>
#Html.DisplayFor(modelItem => item.CertDescription)
</td>
<td>
#Html.DisplayFor(modelItem => item.LastModifiedDate)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.CertNo }) |
#Html.ActionLink("Details", "Details", new { id = item.CertNo }) |
#Html.ActionLink("Delete", "Delete", new { id = item.CertNo })
</td>
</tr>
}
</table>
My Context:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
static ApplicationDbContext()
{
// Set the database intializer which is run once during application start
// This seeds the database with admin user credentials and admin role
Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer());
}
public override int SaveChanges()
{
try
{
return base.SaveChanges();
}
catch (DbEntityValidationException ex)
{
string errorMessages = string.Join("; ", ex.EntityValidationErrors.SelectMany(x => x.ValidationErrors).Select(x => x.PropertyName + ": " + x.ErrorMessage));
throw new DbEntityValidationException(errorMessages);
}
}
public DbSet<CompanyAdmin> CompanyDB { get; set; }
public DbSet<Certificate> CertificateDB { get; set; }
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
But the results keep coming up empty for the 2 join columns, please see screenshot here
Any idea what I've done wrong?

In your query you populate property CompanyName, but in your view you render property Company. Same goes for User in view vs UserName in a query.
Also I recommend adding .ToList() just before you pass the model to your view - this will make sure data is extracted from DB into objects before it is passed to your view:
model = (from c in db.CertificateDB
join u in db.Users on c.User equals u.Id
join d in db.CompanyDB on c.Company equals d.Id
select new CertificateViewModel
{
CertNo = c.CertNo,
UserName = u.UserName,
CompanyName = d.CompanyName,
CertDescription = c.CertDescription,
LastModifiedDate = c.LastModifiedDate
}
).ToList();

You are setting UserName and CompanyName property for your CertificateViewModel in controller action:
UserName = u.UserName,
CompanyName = d.CompanyName,
while in View you are using Company and User property:
<td>
#Html.DisplayFor(modelItem => item.Company)
</td>
<td>
#Html.DisplayFor(modelItem => item.User)
</td>
So you either need to set the Company and User property of your view model in controller or use CompanyName and UserName for rendering in View, if you change the view, change it to use the correct properties :
<td>
#Html.DisplayFor(modelItem => item.CompanyName)
</td>
<td>
#Html.DisplayFor(modelItem => item.UserName)
</td>

Related

FullName from Identity is not working asp .net core 3.0

I am working on a small project and trying to display the fullname (which added by me on in ApplicationUser Model inhireted from IdentityUser) and below the Model:
public class ApplicationUser : IdentityUser
{
public int PersonnalNumber { get; set; }
public string FullName { get; set; }
}
here is SystemDetails Model have relationship with Application User:
public class SystemDetails
{
[Key]
public int Id { get; set; }
[Required]
[Display(Name = "System Name")]
public string SystemName { get; set; }
[Required]
[Display(Name = "Admin Name")]
public string SystemAdminId { get; set; }
public string ServerNames { get; set; }
[ForeignKey("SystemAdminId")]
public virtual ApplicationUser ApplicationUser { get; set; }
}
and here is the Index View:
#if (Model.Count() > 0)
{
<table class=" table table-striped border">
<tr class="table-secondary">
<th>
#Html.DisplayNameFor(m => m.SystemName)
</th>
<th>
#Html.DisplayNameFor(m => m.SystemAdminId)
</th>
<th></th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(m => item.SystemName)
</td>
<td>
#Html.DisplayFor(m => item.ApplicationUser.FullName)
</td>
<td>
<partial name="_TableButtonPartial" model="#item.Id" />
</td>
</tr>
}
Everything working fine except that FullName is not displayed on index page, I can display SystemAdminId which is the registered user Id but when i try to display the FullName using Applicationuser.FullName it is not displaying any thing! it is saved correctly on the database when I create record on SystemDetails Controller as below:
SystemAdminId
Here is create action:
[HttpPost,ActionName("Create")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> CreatePost()
{
List<ApplicationUser> userList = new List<ApplicationUser>();
if (!ModelState.IsValid)
{
return NotFound();
}
userList = await (from user in _db.ApplicationUser select user).ToListAsync();
ViewBag.usersList = userList;
_db.SystemDetails.Add(SystemDetails);
await _db.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
Appreciating any help
In controller , when querying the SystemDetails list you should load the related ApplicationUser :
using Microsoft.EntityFrameworkCore;
var result = _dbContext.SystemDetails.Include(f => f.ApplicationUser).ToList();

ASP.NET MVC limit Table view depending on user role

So I'm building a web app for tracking holidays across a company that has different sites. I need to display list of employees on my admin page but I only want Managers/Admins to view the employee list related to them based on their sites (they may have one or many).
On my Admin page, I have created a table of employees from my database, which displays all employees and links to their details on each row.
Controller :
public ActionResult Index(int? page, string searchString)
{
var employees = db.Employees.Include(e => e.Area).Include(e => e.Discipline).Include(e => e.Shift).Include(e => e.Site).Include(e => e.UserRole);
return View(employees.ToList().ToPagedList(page ?? 1, 10 ));
}
Model:
public partial class Employee
public Employee()
{
this.HolidayRequestForms = new HashSet<HolidayRequestForm>();
}
public int EmployeeID { get; set; }
public string FullName { get; set; }
[Required(ErrorMessage = "This Field is Required")]
public string EmailID { get; set; }
[Required(ErrorMessage = "This Field is Required")]
public string Password { get; set; }
public System.DateTime StartDate { get; set; }
public int RoleID { get; set; }
public int ShiftID { get; set; }
public int AreaID { get; set; }
public int DisciplineID { get; set; }
public int SiteID { get; set; }
public int ALCategory { get; set; }
public Nullable<int> HoursTaken { get; set; }
public Nullable<int> AwardedLeave { get; set; }
public Nullable<int> TotalHoursThisYear { get; set; }
public int HoursCarriedForward { get; set; }
public Nullable<int> EntitlementRemainingThisYear { get; set; }
public string Comments { get; set; }
public int SickLeaveTaken { get; set; }
public Nullable<int> SickLeaveEntitlement { get; set; }
public Nullable<int> SickLeaveEntitlementRemaining { get; set; }
public int StudyLeaveEntitlement { get; set; }
public int StudyLeaveTaken { get; set; }
public Nullable<int> StudyLeaveRemaining { get; set; }
public int ExamLeaveTaken { get; set; }
public int ForceMajeure { get; set; }
public int BereavementLeaveTaken { get; set; }
public int MaternityLeaveTaken { get; set; }
public int ParentalLeaveTaken { get; set; }
public int AdoptionLeaveTaken { get; set; }
public string LoginErrorMessage { get; set; }
public virtual Area Area { get; set; }
public virtual Discipline Discipline { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<HolidayRequestForm> HolidayRequestForms { get; set; }
public virtual Shift Shift { get; set; }
public virtual Site Site { get; set; }
public virtual UserRole UserRole { get; set; }
}
And View (just the table section):
<table class="table table-striped">
<tr>
<th>
Name
</th>
<th>
Start Date
</th>
<th>
Area
</th>
<th>
Discipline
</th>
<th>
Site Name
</th>
<th>
AL Category
</th>
<th>
Hours CF
</th>
<th>
Awarded Leave
</th>
<th>
Total Hours This Year
</th>
<th>
Hours Taken
</th>
<th>
Hours Remaining
</th>
<th>
Role
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.FullName)
</td>
<td>
#Html.DisplayFor(modelItem => item.StartDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.Area.Area1)
</td>
<td>
#Html.DisplayFor(modelItem => item.Discipline.Discipline1)
</td>
<td>
#Html.DisplayFor(modelItem => item.Site.SiteName)
<td>
#Html.DisplayFor(modelItem => item.ALCategory)
</td>
<td>
#Html.DisplayFor(modelItem => item.HoursCarriedForward)
</td>
<td>
#Html.DisplayFor(modelItem => item.AwardedLeave)
</td>
<td>
#Html.DisplayFor(modelItem => item.TotalHoursThisYear)
</td>
<td>
#Html.DisplayFor(modelItem => item.HoursTaken)
</td>
<td>
#Html.DisplayFor(modelItem => item.EntitlementRemainingThisYear)
</td>
<td>
#Html.DisplayFor(modelItem => item.UserRole.RoleName)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.EmployeeID }, new { #class = "btn-xs btn-warning glyphicon glyphicon-pencil" })
#Html.ActionLink("Details", "Details", new { id = item.EmployeeID }, new { #class = "btn-xs btn-info glyphicon glyphicon-info-sign" })
#Html.ActionLink("Delete", "Delete", new { id = item.EmployeeID }, new { #class = "btn-xs btn-danger glyphicon glyphicon-trash" })
</td>
</tr>
}
</table>
#Html.PagedListPager(Model, page => Url.Action("Index", new { page }))
I'd like it so that only managers/Admins assigned to certain sites could only view those sites and none else. Regular Users don't have access to this page.
Is this possible to do in mvc??

Save the List value during the post back, its get cleared when i try to access the list after clicking the button each time in MVC

Controller:
List<EmployeeSkill> emp = new List<EmployeeSkill>();
public ActionResult viewskills(EmployeeSkill objskillset)
{
emp .Add(objskillset);
return PartialView("_SkillListPartial", objskillset);
}
Model:
public int EmployeeID { get; set; }
[Required(ErrorMessage = "Please Enter Skill")]
public string SkillName { get; set; }
[Display(Name = "Experience (In Months)")]
[Required(ErrorMessage = "Please Enter Experience(In Months)")]
public Nullable<byte> ExperienceInMonths { get; set; }
public string CreatedBy { get; set; }
public Nullable<System.DateTime> CreatedDate { get; set; }
public string ModifiedBy { get; set; }
public Nullable<System.DateTime> ModifiedDate { get; set; }
public Nullable<bool> IsActive { get; set; }
public virtual EmployeeDetail EmployeeDetail { get; set; }
View:
model IEnumerable<CISSEC.Models.EmployeeSkill>
<table class="table">
<tr>
<th> #Html.DisplayNameFor(model => model.SkillName) </th>
<th> #Html.DisplayNameFor(model => model.ExperienceInMonths)</th>
</tr>
#foreach (var item in Model) {
<tr>
<td> #Html.DisplayFor(modelItem => item.SkillName) </td>
<td> #Html.DisplayFor(modelItem => item.ExperienceInMonths) </td>
</tr>
}
</table>
Your list is not posted back because you do not render <input> elements for the properties of the list items. Use HiddenFor to render the inputs. Use a for loop so the modelbinder receives the correct index of the list items.
#for (var i = 0; i < Model.Count(); i++) {
<tr>
<td> #Html.HiddenFor(m => m[i].SkillName) </td>
<td> #Html.HiddenFor(m=> m[i].ExperienceInMonths) </td>
</tr>
}

Display a list in a view MVC 4

I have a model Course, a model Component and a model Evaluation:
public class Course
{
public virtual int CourseId { get; set; }
public virtual string Name { get; set; }
public virtual List<Component> Components { get; set; }
public virtual List<UserProfile> Users { get; set; }
public virtual List<Evaluation> Evaluation { get; set; }
}
public class Component
{
public virtual int ComponentId { get; set; }
public virtual int CourseId { get; set; }
public virtual Course Course { get; set; }
public virtual string NameComp { get; set; }
}
public class Evaluation
{
public virtual int EvaluationId { get; set; }
public virtual int CourseId { get; set; }
public virtual Course Course { get; set; }
public virtual int UserId { get; set; }
public virtual UserProfile User { get; set; }
public virtual int Grade { get; set; }
}
I need to show in a view a table with all the users, all the components created and the grade for each one.
I tried this way:
#model SGP.Models.Course
<table>
<tr>
<th>
Username
</th>
#foreach (var x in Model.Components)
{
<th>
#Html.DisplayFor(modelItem => x.NameComp)
</th>
}
<th></th>
</tr>
#foreach (var item in Model.Evaluation)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.User.UserName)
</td>
#foreach (var x in Model.Components)
{
<td>
#Html.DisplayFor(modelItem => item.Grade)
</td>
}
<td>
</td>
</tr>
}
But this gives me all the components in one column, and i need one column for each component, and a grade for each one:
The code i have gives this:
Username - Component1Component2Component3
Test - 12
Test - 13
Test - 10
(example of result with username and grades)
And i need:
Username - Component1 - Component2 - Component3
Test - 12 - 13 - 10
(example of result with username and grades)
How can i do this? Thanks
The definition of Evaluations in Course should be:
public virtual IGrouping<string, Evaluation> Evaluations { get; set; }
The code should be:
#model SGP.Models.Course
<table>
<tr>
<th>
Username
</th>
<th>
#foreach (var x in Model.Components)
{
#Html.DisplayFor(modelItem => x.NameComp)
}
</th>
<th></th>
</tr>
#foreach (var group in Model.Evaluations)
{
<tr>
<td>
#Html.DisplayFor(modelItem => group.Key)
</td>
#foreach (var item in group)
{
<td>
#Html.DisplayFor(modelItem => item.Grade)
</td>
}
<td>
</td>
}
</tr>
You need to make sure the evaluation is in reference to a course component:
public class Evaluation
{
public virtual int EvaluationId { get; set; }
public virtual int CourseId { get; set; }
public virtual Course Course { get; set; }
public virtual int ComponentId { get; set; }
public virtual Component Component { get; set; }
public virtual int UserId { get; set; }
public virtual UserProfile User { get; set; }
public virtual int Grade { get; set; }
}
Here are some test values:
var users = new List<UserProfile>
{
new UserProfile { UserId = 1, UserName = "Jim" },
new UserProfile { UserId = 2, UserName = "Sam" },
};
var components = new List<Component>
{
new Component { ComponentId = 1, NameComp = "Unit 1" },
new Component { ComponentId = 2, NameComp = "Unit 2" }
};
var course = new Course
{
Users = users,
Components = components.OrderBy(c => c.ComponentId).ToList(),
Evaluation = new List<Evaluation>
{
new Evaluation { User = users[0], ComponentId = components[0].ComponentId, Grade = 87 },
new Evaluation { User = users[0], ComponentId = components[1].ComponentId, Grade = 99 },
new Evaluation { User = users[1], ComponentId = components[0].ComponentId, Grade = 75 },
new Evaluation { User = users[1], ComponentId = components[1].ComponentId, Grade = 65 }
}
};
And following Razor view should do what you need:
#model SGP.Models.Course
<table>
<tr>
<th>
Username
</th>
#foreach (var x in Model.Components)
{
<th>
#Html.DisplayFor(modelItem => x.NameComp)
</th>
}
<th></th>
</tr>
#foreach (var userEvaluation in Model.Evaluation.GroupBy(e => e.User))
{
<tr>
<td>
#Html.DisplayFor(modelItem => userEvaluation.Key.UserName)
</td>
#foreach (var x in Model.Components)
{
<td>
#(userEvaluation.FirstOrDefault(e => e.ComponentId == x.ComponentId)?.Grade)
</td>
}
<td></td>
</tr>
}
Watch out for this model, it has a lot of circular references, which can be problematic if you're using something like Entity Framework.

How to display data from current user that's logged in

I want to display the events of the user that is currently logged on
How do I do that?
Here is my code:
This is my Model
public Event()
{
Venues = new HashSet<Venue>();
Ratings = new HashSet<Rating>();
}
public int EventID { get; set; }
[Required]
[StringLength(50)]
[Display(Name="Event Name")]
public string EventName { get; set; }
[Required]
[StringLength(100)]
[Display(Name = "Event Description")]
public string EventDesc { get; set; }
[Column(TypeName = "image")]
[Display(Name = "Event Logo")]
public byte[] EventLogo { get; set; }
[StringLength(50)]
[Display(Name = "Event Location")]
public string EventLocation { get; set; }
public virtual AspNetUser AspNetUser { get; set; }
Here is my controller:
public ActionResult ManageEvent()
{
if (!User.Identity.IsAuthenticated)
{
return RedirectToAction("Login", "Account");
}
var events = db.Events;
return View(events.ToList());
}
Here is my View:
#model IEnumerable<Project_Touchee.Models.Event>
#{
ViewBag.Title = "Manage Events";
}
<h2>Manage All Events</h2>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.EventLogo)
</th>
<th>
#Html.DisplayNameFor(model => model.EventName)
</th>
<th>
#Html.DisplayNameFor(model => model.EventDesc)
</th>
<th>
#Html.DisplayNameFor(model => model.EventLocation)
</th>
#foreach (var item in Model)
{
<tr>
<td>
#{
byte[] eventt = item.EventLogo;
string imageSrc = null;
if (item.EventLogo != null)
{
MemoryStream ms = new MemoryStream();
ms.Write(eventt, 0, eventt.Length);
string imageBase64 = Convert.ToBase64String(ms.ToArray());
imageSrc = string.Format("data:image/index;base64,{0}", imageBase64);
}
}
<img src="#imageSrc" width="100" height="100" />
</td>
<td>
#Html.DisplayFor(modelItem => item.EventName)
</td>
<td>
#Html.DisplayFor(modelItem => item.EventDesc)
</td>
<td>
#Html.DisplayFor(modelItem => item.EventLocation)
</td>
This should only display the events that the current user created.
First, you need to get a copy of the current user:
var user = UserManager.FindById(User.Identity.GetUserId());
Then, you need to query the events using that:
var events = db.Events.Where(m => m.AspNetUser == user);
You can make your life simpler by adding a navigation property to AspNetUser for events:
public virtual ICollection<Event> Events { get; set; }
Then, you can just use: user.Events

Resources