-1

I made a dropdown list for me to assign Admin Roles to certain users when I create them:

Create user form

But they don't assign themselves properly, as you can see here:

User overview form

It happens because of this line Value = "Administrator LVL2". My question is: How do i assign it to my model like I've done for assigning last names:

    <div class="editor-field">
        @Html.EditorFor(model => model.LastName)
        @Html.ValidationMessageFor(model => model.LastName)
    </div>

Views\User\Create.cshtml

  <div class="editor-label">
        @{
                List<SelectListItem> listItems = new List<SelectListItem>();
                listItems.Add(new SelectListItem
                {
                    Text = "Administrator LVL1",
                    Value = model => model.AdminRole, <-- THIS IS WRONG
            });
            listItems.Add(new SelectListItem
            {
                Text = "Administrator LVL2",
                Value = "Administrator LVL2",
                Selected = true
            });
            listItems.Add(new SelectListItem
            {
                Text = "Administrator LVL3",
                Value = "Administrator LVL3"
            });
        }

        @Html.DropDownListFor(model => model.AdminRole, listItems, "-- Select Admin Role --")
    </div>

UserController.cs

    public class UserController : Controller
    {
        private IssueContext db = new IssueContext();

        //
        // GET: /User/

        public ViewResult Index(string sortOrder, string currentFilter, string searchString, int? page)
        {
            ViewBag.CurrentSort = sortOrder;
            ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
            ViewBag.DateSortParm = sortOrder == "Date" ? "date_desc" : "Date";

            if (searchString != null)
            {
                page = 1;
            }
            else
            {
                searchString = currentFilter;
            }

            ViewBag.CurrentFilter = searchString;

            var users = from s in db.Users
                        select s;
            if (!String.IsNullOrEmpty(searchString))
            {
                users = users.Where(s => s.LastName.ToUpper().Contains(searchString.ToUpper())
                                       || s.FirstMidName.ToUpper().Contains(searchString.ToUpper()));
            }
            switch (sortOrder)
            {
                case "name_desc":
                    users = users.OrderByDescending(s => s.LastName);
                    break;
                case "Date":
                    users = users.OrderBy(s => s.EnrollmentDate);
                    break;
                case "date_desc":
                    users = users.OrderByDescending(s => s.EnrollmentDate);
                    break;
                default:  // Name ascending 
                    users = users.OrderBy(s => s.LastName);
                    break;
            }

            int pageSize = 5;
            int pageNumber = (page ?? 1);
            return View(users.ToPagedList(pageNumber, pageSize));
        }

        //
        // GET: /User/Details/5

        public ActionResult Details(int id = 0)
        {
            User user = db.Users.Find(id);
            if (user == null)
            {
                return HttpNotFound();
            }
            return View(user);
        }

        //
        // GET: /User/Create

        public ActionResult Create()
        {
            return View();
        }

        //
        // POST: /User/Create

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create(
            [Bind(Include = "LastName, FirstMidName, EnrollmentDate, DepartmentID, DepotID")]
            User user)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    db.Users.Add(user);
                    db.SaveChanges();
                    return RedirectToAction("Index");

                }
            }
            catch (DataException /* dex */)
            {
                //Log the error (uncomment dex variable name after DataException and add a line here to write a log.
                ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
            }

            return View(user);
        }

        //
        // GET: /User/Edit/5

        public ActionResult Edit(int id = 0)
        {
            User user = db.Users.Find(id);
            if (user == null)
            {
                return HttpNotFound();
            }
            return View(user);
        }

        //
        // POST: /User/Edit/5

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit(
           [Bind(Include = "UserID, LastName, FirstMidName, EnrollmentDate, DepartmentID, DepotID")]
   User user)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    db.Entry(user).State = EntityState.Modified;
                    db.SaveChanges();
                    return RedirectToAction("Index");
                }
            }
            catch (DataException /* dex */)
            {
                //Log the error (uncomment dex variable name after DataException and add a line here to write a log.
                ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
            }
            return View(user);
        }

        //
        // GET: /User/Delete/5

        //This code accepts an optional Boolean parameter that indicates whether it was called after a failure to save changes. 
        //This parameter is false when the HttpGet Delete method is called without a previous failure. When it is called by the 
        //HttpPost Delete method in response to a database update error, the parameter is true and an error message is passed to the view.


        public ActionResult Delete(bool? saveChangesError = false, int id = 0)
        {
            if (saveChangesError.GetValueOrDefault())
            {
                ViewBag.ErrorMessage = "Delete failed. Try again, and if the problem persists see your system administrator.";
            }
            User user = db.Users.Find(id);
            if (user == null)
            {
                return HttpNotFound();
            }
            return View(user);
        }

        //
        // POST: /User/Delete/5

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Delete(int id)
        {
            try
            {
                User user = db.Users.Find(id);
                db.Users.Remove(user);
                db.SaveChanges();
            }
            catch (DataException/* dex */)
            {
                // uncomment dex and log error. 
                return RedirectToAction("Delete", new { id = id, saveChangesError = true });
            }
            return RedirectToAction("Index");
        }


        //To make sure that database connections are properly closed and the resources they hold freed up, you should see to it that the context instance is disposed. 

        protected override void Dispose(bool disposing)
        {
            db.Dispose();
            base.Dispose(disposing);
        }
    }

How my classes are mapped:

User to Admin is 1 to 0..1 (I can assign some users with admin status but I don't want every user to have it)

Admin to Ticket is 1 to Many(You can only assign 1 admin(to fix the issue) to a ticket)

User to Ticket is 1 to many (One user can create multiple tickets)

User.cs

public class User
{
    public int UserID { get; set; }
    [StringLength(50, MinimumLength = 1)]
    public string LastName { get; set; }
    [StringLength(50, MinimumLength = 1, ErrorMessage = "First name cannot be longer than 50 characters.")]

    [Column("FirstName")]
    public string FirstMidName { get; set; }

    public string FullName
    {
        get { return LastName + ", " + FirstMidName; }
    }
    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
    public DateTime EnrollmentDate { get; set; }
    public int? AdministratorID { get; set; }
    [ForeignKey("AdministratorID")]
    public virtual Administrator Administrator { get; set; }
    public int DepartmentID { get; set; }
    [ForeignKey("DepartmentID")]
    public virtual Department Department { get; set; }
    public int DepotID { get; set; }
    [ForeignKey("DepotID")]
    public virtual Depot Depot { get; set; }
    public virtual ICollection<Ticket> Tickets { get; set; }
}

Ticket.cs

   public class Ticket
    {
        public int TicketID { get; set; }
        public string Issue { get; set; }
        [DisplayFormat(NullDisplayText = "No Priority")]
        public Priority? Priority { get; set; }
        [ForeignKey("CategoryID")]
        public virtual Category Category { get; set; }
        public int CategoryID { get; set; }
        public int UserID { get; set; }
        [ForeignKey("UserID")]
        public virtual User User { get; set; }


        public int AdministratorID { get; set; }
        [ForeignKey("AdministratorID")]
        public virtual Administrator Administrator { get; set; }
    }

Administrator.cs

public class Administrator
{
    public int AdministratorID { get; set; }
    public string AdministratorTitle { get; set; }
    public virtual ICollection<User> Users { get; set; }

}
TykiMikk
  • 1,058
  • 3
  • 15
  • 31
  • It's not your view that's going to be causing the problem, it's going to be in your controller / when you save the data. – Gareth Mar 10 '16 at 18:40
  • Can you please show the Action where you create the User? – DCruz22 Mar 10 '16 at 18:58
  • 2
    I would recommend storing your roles in a db, if you have one. Each role would have an ID (e.g., Administrator LVL 1 = 1, Administrator LVL 2 = 2, Administrator LVL 3 = 3). You can get a data pull from the db and you can bind the dropdown list to the model. So, whatever the Admin lvl ID the user has will match the ID from the database. – Jason Cidras Mar 10 '16 at 19:02
  • I am in agreement with @JasonCidras on this one.. if you have a database that holds user's.. you need a foreign key in that database to store the ID of the role of the user.. or you could just have 1 table that holds that user's role.. depending on your project.. if you want to create a dropdownlist I would advise to create 2 tables.. 1 for the User info and another for possible roles.. then in the controller of your User Table you could stuff the roles into a viewbag to populate a dropdownlist `public ActionResult Create() { ViewBag.role = new SelectList(database.roleTable), "ID", "text"); }` – Grizzly Mar 10 '16 at 19:11
  • so with the code you just uploaded.. just because you successfully added a dropdownlist with the values you want doesn't mean it is going to magically work.. where is the database going to store that value(role) for that user if it doesn't have a place (property) for it? from what it looks like, all you need to do is add another table very similar to the tables I am assuming you created to hold Departments and Depots? – Grizzly Mar 10 '16 at 20:12
  • @BviLLe_Kid I re-edited my code. I actually had a table before called Adminstrator Table and I also had a Administrator class. A person from another question advised me to delete it and just use AdminRole like a Usertype or extend my administrator class. I've uploaded my original 3 classes! – TykiMikk Mar 10 '16 at 20:23
  • okay so just to be clear.. you do or do not have the administrator table anymore? If you do.. your Foreign Key needs to be in the `User` Class.. so create `public int administratorID { get; set; }` and give it the `[ForeignKey("Administrator")]` annotation... and how/why is your Primary Key in your Administrator table nullable? it shouldn't be – Grizzly Mar 10 '16 at 20:34
  • I do if it can fix the issue. The Primary Key in my administrator is nullable because not every user will be assigned a Admin ID. If you look into this link: http://stackoverflow.com/questions/35875453/insert-statement-conflicted-with-the-foreign-key/35877245?noredirect=1#comment59505532_35877245 I had this issue to begin with and someone told me to delete administrator class. – TykiMikk Mar 10 '16 at 20:48
  • okay, how many values are you planning on entering into the Administrators table? From what I see you only had 1 column, `AdminID`.. so if you wanted your view to display only the ID then that's all you need, but if you want your view to display the actual word "Administrator" then you need another property in the Administrator table.. so in the Administrator table you would need AdminID, text.. text is the property name to hold the string value "Administrator" and all other types of roles – Grizzly Mar 10 '16 at 21:01
  • Remove your `[Bind]` attribute which specifically excludes the `AdminRole` from binding. Then scrap all this and start using [view models](http://stackoverflow.com/questions/11064316/what-is-viewmodel-in-mvc) –  Mar 10 '16 at 21:27

2 Answers2

2

Here is what I would recommend:

1) Make a Roles Table (if you have done ASP.NET Membership, this is already provided).

Role:
   RoleId Int
   RoleName String

2) Add Roles into the table (you can use SQL Server [or any SQL you are using])

3) Add a ForeignKey to your User OR add a link table like UsersInRoles (once again, if you used ASP Membership this is added)

1st Example:
    User:
       UserId Int
       FirstName String
       LastName string
       DepotId Int
       DepartmentId Int
       RoleId Int

2nd Example:
    UsersInRole
        UserId Int
        RoleId Int

Now once you GET a user, you can bring back the RoleId:

public ActionResult List()
{
    // Get Roles
    ViewBag.Roles = (from role in dbContext.Roles
                     select new SelectListItem 
                     {
                         Text = role.RoleName,
                         Value = role.RoleId
                      });
    // Get Users
    IEnumerable<User> users = (from user in dbContext.Users
                               select new User 
                               {
                                  UserId = user.UserId,
                                  FirstName = user.FirstName,
                                  LastName = user.LastName,
                                  DepotId = user.DepotId,
                                  DepartmentId = user.DepartmentId,
                                  RoleId = user.RoleId,
                                  // OR
                                  // RoleId = dbContext.Roles.Where(r => r.UserId == user.UserId).First().RoleId
                                  //
                               });
      return users;
}

In your view:

<div>
    @Html.DropDownListFor(model => model.RoleId, (SelectList)ViewBag.Roles)
</div>
Jason Cidras
  • 509
  • 5
  • 11
  • I followed your step 1 and 2 but the code for the controller is far too confusing for me to understand. I put up my usercontroller class. Can you please try to re-edit your solution on my code please. – TykiMikk Mar 13 '16 at 03:10
1

if you have 2 tables in your database.. one that holds the User Info (for arguments sake the name of the table will be User), and the other that holds the possible roles (name of table is Role).. you can create a property in the User table called roleID(foreign key) to hold the Primary Key (ID) of the Role Table. So in the Role table let's say you have 2 properties, ID and text. The ID holds the unique value to represent the text. e.g ID = 1, text = Administrator... ID = 2, text = Member... so on and so on... then when you create a user, based on the example you gave above, you would see this is your User table test 2 test2 2016-11-03 1 1 1 //if you made him an administator

In your Details view you can display the text and not the ID by making sure that in your User model you have public virtual Role role { get; set; }

Then:

@Html.DisplayNameFor(model => model.Role.text)

Then in your User Controller under the Create Action you stuff the possible roles in a ViewBag:

public ActionResult Create()
{
    ViewBag.roleID = new SelectList(database.Role, "ID", "text");
    return View()
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ID, firstName, lastName, enrollmentDate, departmentID, depotID, roleID")] User user)
{
    if(ModelState.IsValid)
    {
        ViewBag.roleID = new SelectList(database.Role, "ID", "text", user.roleID);
        return View(user);
    }
}

Then in your Create cshtml page :

@Html.DropDownList("roleID", null, htmlAttributes: new { @class = "form-control" }) 

assuming you are using bootstrap for the form-control class name.

Grizzly
  • 5,873
  • 8
  • 56
  • 109
  • I've created the tables FINALLY! So my User table has AdminID and my admin table has AdminID and a Text. Here is where I want to ask you for advice. In my Administrator table my text is actually Administrator lvl 1 and Administrator lvl 2, In the comment you gave you put in Administrator or Member. If I follow your method I won't be able to identify "which" Admin the ticket was assigned to since I have more than one Admin. My Ticket table has TicketID, UserID(Person who opened the ticket) and AdminID(The admin that's been assigned the ticket) . – TykiMikk Mar 13 '16 at 02:43
  • Okay, when I meant "Admin" and/or "Member" they were just examples.. so your "Administrator lvl 1" and "Administrator lvl 2" are perfectly fine. – Grizzly Mar 13 '16 at 15:46
  • @JasonWan did you get what you were looking for? – Grizzly Mar 14 '16 at 18:34
  • Yeah kind of but I'm refactoring everything again since someone suggested me not to use an admin class. – TykiMikk Mar 14 '16 at 18:58