1

I have looked around and found some close answers, but I haven't seen one yet like this:

Using Entity Framework I have the following:

A Role model:

public class Role
{
    [Key]
    public short RoleId { get; set; }
    public string RoleName { get; set; }
    public string RoleDescription { get; set; }
}

A User model:

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public string Username { get; set; }

    //more fields etc...

    public virtual ICollection<UserRole> UserRoles { get; set; }
}

and a UserRole model:

public class UserRole
{
    [Key]
    public int UserRoleId { get; set; }
    public int UserId { get; set; }
    public short RoleId { get; set; }
    public virtual Role Role { get; set; }
}

What I am trying to do is determine how to compose a viewmodel such that I can display a list of all available roles when creating a new user and a list of available+selected roles when editing a user. I can achieve the first part already using a foreach, but I feel like its dirty.

In all of the examples I have seen, the entire viewmodel is wrapped in an IEnumerable on main view and is rendered using @Html.EditorForModel() with an editor template. This seems to allow for automagic mapping of the view data back into the underlying model. I would like to achieve this using the same technique, but I can't seem to wrap my head around handling the collection of Role/UserRole within a singular User model.

StackOverflow question I am referencing: Generate Dynamically Checkboxes, And Select Some of them as Checked

Community
  • 1
  • 1
  • "I feel like it's dirty" is not a sufficient reason to abandon a technique. If it's causing you maintenance headaches, then by all means do something else, but don't dismiss an idea just because someone says it's a bad practice. – Robert Harvey Sep 18 '14 at 22:26
  • Your models don't have a property indicating if a role is selected for a user so you will need to create view models to represent what you want to display/edit –  Sep 18 '14 at 22:29
  • @stephen-muecke I understand that I should be using a view model. My primary point of confusion is on how to define a view model and then implement it in the editor template such that it only iterates over those properties which are IEnumerable/ICollections. –  Sep 18 '14 at 22:34
  • In both create and edit modes, do you want to display editable details of the user (name, email etc) and a collection of all roles with checkboxes to indicate if the role is selected for the user? –  Sep 18 '14 at 22:45

1 Answers1

1

I would suggest 2 view models for editing

public class RoleVM
{
  public short RoleId { get; set; }
  public string RoleName { get; set; }
  public bool IsSelected { get; set; }
}
public class UserVM
{
  public int Id { get; set; }
  public string Name { get; set; }
  public List<RoleVM> Roles { get; set; }
}

GET method

public ActionResult Edit(int ID)
{
  UserVM model = new UserVM();
  // map all avaliable roles to model.Roles
  // map user to model, including setting the IsSelected property for the users current roles
  return View(model);
}

View

@model YourAssembly.UserVM
...
@Html.TextBoxFor(m => m.Name)
...
@EditorFor(m => m.Roles)

EditorTemplate (RoleVM.cshtml)

@model YourAssemby.RoleVM
@Html.HiddenFor(m => m.RoleId) // for binding
@Html.CheckBoxFor(m => m.IsSelected) // for binding
@Html.DisplayFor(m => Name)

POST method

[HttpPost]
public ActionResult Edit(UserVM model)
{
  // model.Roles now contains the ID of all roles and a value indicating if its been selected
  • This works fairly well. I had an issue with parameter bindings on my create POST controller and it made me think my view models were broken earlier. I went ahead and removed them per your example and it seems to be working well. –  Sep 18 '14 at 23:33