Add Full Identity Role List into Seperate Model - c#

I am trying to add a full list of available roles into an edit user modal. I know how to only list the roles the user has; however, I want to provide the full list so that you can check/uncheck a checkbox on the list and update using "isSelected". I have tried many options found on here and across the internet; however, most of them leave me with a type mismatch (cannot convert Type to EditUserViewModel.Role). I attempted to do it the same way I pulled the roles for the specific user but it pulls "{Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1[Microsoft.AspNetCore.Identity.IdentityRole]}" as the Role and breaks it.
Method:
[HttpGet]
public async Task<IActionResult> EditUser(string id)
{
//GET USER INFORMATION - EXIT IF USER DOESN'T EXIST
var user = await userManager.FindByIdAsync(id);
if (user == null)
{
ViewBag.ErrorMessage = $"User with Id = {id} cannot be found";
return View("NotFound");
}
//USER INFORMATION ---------------------------------------
var model = new EditUserViewModel
{
Id = user.Id,
Email = user.Email,
UserName = user.UserName,
FirstName = user.FirstName,
LastName = user.LastName,
Title = user.Title,
Address = user.Address,
City = user.City,
State = user.State,
//CompanyId = user.CompanyId
};
// ViewBag.SelectedCommpany = user.CompanyId;
//COMPANY DROPDOWN INFO------------------------------------
var company = from c in companyRepository.GetCompanys() select c;
foreach (var c in company)
{
////Store this inforamtion into the company list in the viewmodel
var companyinfo = new EditUserViewModel.CompanyList
{
CompanyName = c.CompanyName,
CompanyID = c.CompanyId
};
model.CompanyLists.Add(companyinfo);
};
//GET LIST OF ROLES(RoleID, RoleName)
var roles = roleManager.Roles;
foreach (var RoleName in roles)
{
//Execute identity method to get full information for the Role and store into an object (roleinfo)
var roleString = Convert.ToString(roles);
var fullRoleInfo = await roleManager.FindByNameAsync(roleString);
//Store this inforamtion into the Role list in the viewmodel
var roleinfo = new EditUserViewModel.Role
{
RoleName = fullRoleInfo.Name,
RoleID = fullRoleInfo.Id
};
model.Roles.Add(roleinfo);
};
}
Model:
namespace PortalDev.Models.ViewModels
{
public class EditUserViewModel
{
public EditUserViewModel()
{
Claims = new List<Claim>();
Roles = new List<Role>();
//CompanyLists = new List<ICompanyRepository>();
CompanyLists = new List<CompanyList>();
}
//ROLES ---------------------------------------------
public class Role
{
public string RoleName { get; set; }
public string RoleID { get; set; }
public bool IsSelected { get; set; }
}
public List<Role> Roles { get; set; }
//CLAIMS----------------------------------------------
public class Claim
{
public string ClaimType { get; set; }
public string ClaimID { get; set; }
}
public List<Claim> Claims { get; set; }
//COMPANY DROPDOWN--------------------------------------
public class CompanyList
{
public string CompanyName { get; set; }
public int CompanyID { get; set; }
}
[Display(Name = "Company")]
public List<CompanyList> CompanyLists { get; set; } //List of Companies for dropdown
public string SelectedCompany { get; set; }
//USER INFORMATION --------------------------------------
public string Id { get; set; }
//[Required]
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Title { get; set; }
[Required]
[EmailAddress]
public string Email { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
}
}

In the loop you are trying to convert the whole set of roles to the name of one role, instead using the individual role name instead. So just replace the line:
var roleString = Convert.ToString(roles);
with
var roleString = RoleName.Name;
An alternative approach using Linq could look like that:
var allRoleViewModels = roleManager.Roles.Select(x => new EditUserViewModel.Role {RoleID = x.Id, RoleName = x.Name}).ToList();

Related

How To Assign List Value To A Member Of Inner Model Class In C#

public class User
{
public string? UserName{ get; set; }
public string? Password{ get; set; }
public List<UserDetails> Headlist;
}
public class UserDetails
{
public string? FirstName{ get; set; }
public string? LastName { get; set; }
public string? Address { get; set; }
public string? MobileNo { get; set; }
}
I want to insert data from a table into the UserDetails class. I'm unable to access UserDetails List Columns when I access the user model. 
Instead of using
public List<UserDetails> Headlist;
Replace This With In Your Model
public List<UserDetails> Headlist { get; set; } = new List<UserDetails>();
and in C# you can write below code
User model = new User();
model.UserName = "abc";
model.Password = "1234";
//pass your list data to for loop
for (int i = 0; i < List.Count; i++)
{
model.Headlist.Add(new UserDetails()
{
FirstName = List[i].FirstName,
LastName = List[i].LastName,
Address = List[i].Address,
MobileNo = List[i].MobileNo
});
}
return model;

Entity Framework automatically inserts new row in parent table

I'm using an UI to insert data into the DB. Here is my entity model and controller. Whenever I'm inserting data into the UserDetail table, it automatically creates a new row in the UserRole table. Not sure why it's happening like this. For now UserRole is hard-coded in controller.
public class UserDetail
{
[Key]
public int UserID { get; set; }
[Required]
[StringLength(30, MinimumLength = 4)]
public string UserName { get; set; }
[Required]
[StringLength(50, MinimumLength = 4)]
public string FirstName { get; set; }
[Required]
[StringLength(50, MinimumLength = 4)]
public string LastName { get; set; }
[Required]
[EmailAddress]
[StringLength(150, MinimumLength = 4)]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
[StringLength(30,MinimumLength=4)]
public string Password { get; set; }
public UserRole UserRole { get; set; }
}
public class UserRole
{
[Key]
public int RoleID { get; set; }
[Required]
[StringLength(20,MinimumLength=5)]
public string RoleName { get; set; }
public IEnumerable<UserDetail> UserDetail { get; set; }
}
[HttpPost]
public HttpResponseMessage Register(UserDetail usrInfo)
{
UserContext ctx = new UserContext();
UserDetail user = new UserDetail
{
UserRole = ctx.UserRole.Where(id => id.RoleID == 2).Select(r => r).FirstOrDefault(),
FirstName = usrInfo.FirstName,
LastName = usrInfo.LastName,
UserName = usrInfo.UserName,
Password = usrInfo.Password,
Email = usrInfo.Email,
};
_unitofwork.userDetail.Add(user);
if (_unitofwork.Completed() > 0)
return Request.CreateResponse(HttpStatusCode.OK, "Created");
else
return Request.CreateResponse();
}
public class UserContext: DbContext
{
public UserContext():base()
{
Database.SetInitializer<UserContext>(new CreateDatabaseIfNotExists<UserContext>());
//Database.SetInitializer<UserContext>(new DropCreateDatabaseIfModelChanges<UserContext>());
}
public DbSet<UserDetail> UserDetails { get; set; }
public DbSet<UserRole> UserRole { get; set; }
}
In the statement where you are instantiating the userdetail object you use a separately defined context to query for the user role:
UserContext ctx = new UserContext();
UserDetail user = new UserDetail
{
**UserRole = ctx.UserRole.Where(id => id.RoleID == 2).Select(r => r).FirstOrDefault(),**
FirstName = usrInfo.FirstName,
LastName = usrInfo.LastName,
UserName = usrInfo.UserName,
Password = usrInfo.Password,
Email = usrInfo.Email,
};
_unitofwork.userDetail.Add(user);
if (_unitofwork.Completed() > 0)
return Request.CreateResponse(HttpStatusCode.OK, "Created");
else
return Request.CreateResponse()
You then add the user to the userdetail collection under the _unitofwork object which has it's own context. To make thiswork, the userrole object you retrieved has to be under the same context to which you are adding the userdetail object.
So you probably want something like:
UserDetail user = new UserDetail
{
UserRole = _unitofwork.UserRole.Where(id => id.RoleID == 2).Select(r => r).FirstOrDefault(),
FirstName = usrInfo.FirstName,
LastName = usrInfo.LastName,
UserName = usrInfo.UserName,
Password = usrInfo.Password,
Email = usrInfo.Email,
};
_unitofwork.userDetail.Add(user);

I have an error message "An entity object cannot be referenced by multiple instances of IEntityChangeTracker" but not sure of suggested solutions

I am trying to add a user using aspnet.identity and get this error message on
IdentityResult result = manager.Create(user, Password.Text);
the code it is contained in
protected void CreateUser_Click(object sender, EventArgs e)
{
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var signInManager = Context.GetOwinContext().Get<ApplicationSignInManager>();
int x = int.Parse(Address.SelectedValue.ToString());
using (var db = new ApplicationDbContext())
{
physAddress = db.PhysAddress.Find(x);
var user = new ApplicationUser() { UserName = Email.Text, Email = Email.Text, FirstName = FirstName.Text, LastName = LastName.Text, PhoneNumber = PhoneNumber.Text, HomePhone = HomePhone.Text, PhysAddressId = physAddress };
IdentityResult result = manager.Create(user, Password.Text);
if (result.Succeeded)....
I've tried researching error message but not sure how to apply in this example. Any suggestions would be appreciated.
I have a class defined as follows and was using db to get a row from that table using EF
public class PhysAddress
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int PhysAddressId { get; set; }
[Required]
public string Street { get; set; }
[Required]
public string City { get; set; }
[Required]
public string State { get; set; }
[Required]
public string ZipCode { get; set; }
[Required]
And then below ApplicationDbContext in IdentityModels.cs have below
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
public DbSet<PhysAddress> PhysAddress { get; set; }
In IdentityModels have added for each user the property
public virtual PhysAddress PhysAddressId { get; set; }
I was able to resolve by using
((IObjectContextAdapter)db).ObjectContext.Detach(physAddress);

Entity Framework save collection

I have Entity Framework Code First models. When I try save collection of Accounts in one insert i get error message.
public class User
{
[Key]
public int Usr_Id { get; set; }
[Required]
[MaxLength(35)]
public string Name { get; set; }
[Required]
[MaxLength(35)]
public string Surname { get; set; }
[Required]
[MaxLength(35)]
public string Location { get; set; }
//NAVIGATION
public User()
{
UserDevices = new List<UserDevice>();
}
public virtual ICollection<UserDevice> UserDevices { get; set; }
}
public class UserDevice
{
[Key]
public int UsrDev_Id { get; set; }
[Required]
[MaxLength(50)]
public string PurposeOfUse { get; set; }
// NAVIGATION
public UserDevice()
{
Accounts = new List<Account>();
}
//User can have many UserDevice
public int Usr_Id { get; set; }
public virtual User User { get; set; }
//UserDevice can have many Acoount
public virtual ICollection<Account> Accounts { get; set; }
//One to one
public virtual SoftwareInformation SoftwareInformation { get; set; }
public virtual HardwareInformation HardwareInformation { get; set; }
}
public class Account
{
[Key]
public int Acc_Id { get; set; }
public string Name { get; set; }
//NAVIGATION
//UserDevice can have many Account
public int UsrDev_Id { get; set; }
public virtual UserDevice UserDevice { get; set; }
}
Insert of new UserDevice
List<Account> accountsList = new List<Account>();
foreach (var item in model.DeviceInformations.OS.Accounts)
{
accountsList.Add(new Account { Name = item.Name });
}
_unitOfWork.UserDevices.Add(new UserDevice
{
Usr_Id = model.Usr_Id,
PurposeOfUse = model.PurposeOfUse,
HardwareInformation = new HardwareInformation
{
MB_Manufacturer = model.DeviceInformations.Motherboard.Manufacturer,
MB_Model = model.DeviceInformations.Motherboard.Model,
MB_Name = model.DeviceInformations.Motherboard.Name,
MB_UUID = model.DeviceInformations.Motherboard.UUID,
CPU_Manufacturer = model.DeviceInformations.Processor.Manufacturer,
CPU_MaxClockSpeed = model.DeviceInformations.Processor.MaxClockSpeed,
CPU_Name = model.DeviceInformations.Processor.Name,
},
SoftwareInformation = new SoftwareInformation
{
OS_Edition = model.DeviceInformations.OS.Edition,
OS_HostName = model.DeviceInformations.OS.HostName,
OS_Language = model.DeviceInformations.OS.Language,
OS_Platform = model.DeviceInformations.OS.Platform,
OS_ProductKey = model.DeviceInformations.OS.ProductKey,
OS_ServicePackVersion = model.DeviceInformations.OS.ServicePackVersion,
OS_Version = model.DeviceInformations.OS.Version
},
Accounts = accountsList
});
_unitOfWork.Commit();
Error message
{"Cannot insert the value NULL into column 'Acc_Id', table 'LICENSE_WATCHER_TEST.dbo.Accounts'; column does not allow nulls. INSERT fails.\r\nThe statement has been terminated."}
It happends when I try save Accout collection. Is there a way how to save Accouts collection in one Insert?
Acc_id is null on insert. I would expect that ID to be auto generated in cases like this. Is it possible that you have the Acc_id column on the Account Table set up as PK, but not an Identity column in the database?
That might cause the behavior that you are experiencing.
Well, you have Acc_Id defined as Primay key and it seems you are trying to insert a null value to table.
Here you create account list, but you only fill in Name
foreach (var item in model.DeviceInformations.OS.Accounts)
{
accountsList.Add(new Account { Name = item.Name });
}
And then you don't do any changes in accountsList
Before commit you do Accounts = accountsList which doesn't have Id filled in and you try to commit.
Try something like this:
foreach (var item in model.DeviceInformations.OS.Accounts)
{
accountsList.Add(new Account { Acc_Id = !!someIdHere!!, Name = item.Name });
}

What would be the better way of getting linked models values from db

First of all, I'm very new to the ASP.NET MVC C# and EF. I'm in a process of creating a website that should hopefully help me learn these three wonderful technologies. with that said, I have the following models in my project.
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string Lastname { get; set; }
public string EmailAddress { get; set; }
//public string PhoneNumber { get; set; }
public bool? ChangePassword { get; set; }
public bool? Deletable { get; set; }
//Add more Properties for more fields
public virtual ICollection<CompanyInformation> ParentCompanies { get; set; }
public virtual StaffProfile sProfile { get; set; }
}
And
public class StaffProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int StaffProfileId { get; set; }
public string Alias { get; set; }
public StaffGrouping Group { get; set; }
public ICollection<PhoneNumber> PhoneNumbers { get; set; }
public bool isPhoneNumberDisplayed { get; set; }
public bool TextNotificationsAllowed { get; set; }
public bool EmailNotificationsAllowed { get; set; }
public bool PhoneNotificationsAllowed { get; set; }
}
Staff Grouping
public class StaffGrouping
{
public int id { get; set; }
public string GroupName { get; set; }
}
and just for completeness, the phone numbers model
public class PhoneNumber
{
public int id { get; set; }
public string Number { get; set; }
public string Extension { get; set; }
public PhoneType Type { get; set; }
public bool isPrimary { get; set; }
public bool isInActive { get; set; }
}
public enum PhoneType {
Home,
Mobile,
Work,
Other
}
I'm trying to get all the staffs from the db (including the phone numbers, userprofile and group they are linked to) and adding it to a viewmodel for better integration with my view. currently I'm doing it as such:
public ActionResult ManageStaff()
{
using (var repo = new CompanyInformationRepository(new UniteOfWorkCompanies()))
{
var company = repo.FindCompany(User.Identity.Name);
var Users = repo.CompanyStafflookup(company);
var model = new List<StaffManagementViewModel>();
foreach (var user in Users)
{
var group = repo.StaffGroupLookup(user.sProfile);
//var phoneNumber = user.sProfile.PhoneNumbers.Where(p => p.isPrimary == true).FirstOrDefault();
model.Add(new StaffManagementViewModel
{
FirstName = user.FirstName,
LastName = user.Lastname,
EmailAddress = user.EmailAddress,
PhoneNumber = "(915) 433 - 1739", //phoneNumber.Number,
Group = group.GroupName,
UserID = user.UserId
});
}
return View(model);
}
And my repository:
public IQueryable<HoursOfOperation> CompanyHoursLookup(string userName)
{
var company = FindCompany(userName).id;
//var model = _db.HoursOfOperations.Where(e => e.Company.id == company);
var model = from h in _db.HoursOfOperations
where h.Company.id == company
orderby h.Day ascending, h.From ascending
select h;
return model;
}
public IQueryable<UserProfile> CompanyStafflookup(CompanyInformation company)
{
var model = from s in _db.UserProfiles.Include("sProfile")
where s.ParentCompanies.Any(e => e.companyName == company.companyName)
orderby s.FirstName ascending
select s;
return model;
}
public StaffGrouping StaffGroupLookup(StaffProfile Staff)
{
var Staffwithgroup = _db.StaffProfiles.Where(e => e.StaffProfileId == Staff.StaffProfileId).Include("Group").FirstOrDefault();
return Staffwithgroup.Group;
}
I'm guessing there should be a better more efficient way of doing this as I'm counting at least three trips to the database. I tried to use the .include but on the userprofile but since I don't have a navigation Property to point at the group, its giving me an error. the code I'm talking about is the following:
var model = from s in _db.UserProfiles.Include("sProfile").Include("PhoneNumbers").Include("Group")
where s.ParentCompanies.Any(e => e.companyName == company.companyName)
orderby s.FirstName ascending
select s;
Is there a way to achieve this in one call that basically would return a list of UserProfiles that includes the StaffProfile that includes the PhoneNumbers and finally the Group?
You can simply prefix the include with the full path, i.e. use:
Include("sProfile.Group")
This will include both StaffProfile and it's Group.

Categories