c# mvc: Persisting data from View to Controller an

2019-07-11 08:56发布

问题:

I am working with a View that returns List<ViewModel> to the Controller's Create action method.

Questions:

  1. Is it correct to return List<ViewModel> to the controller? The reason I am doing is that I have to make multiple rows entry to the DB for each user. 2. My Controller implemenation is incorrect because I am trying to add data through single User object where I have recieved List of ViewModels which is only the representation of the View for single user. So how the controller should be implemented?
  2. Do I need to have a public ActionResult Create() method in the controller?

Limitations:

  1. Can't change database
  2. None of the User or Role table in the database has int type PK

Logic:

User would be able to select multiple checkboxes(represents ROLE) for each user and that should be persisted in the database as single row. For example

DB: dbo.User table should have the following entries on Save

(abcdefg, levelA, locationB, Role2, null, null, Y)

(msjdhcdu, levelA, locationB, Role2, null, null, Y) Same user Different Role

(msjdhcdu, levelA, locationB, Role3, null, null, Y) Same user Different Role

USer would be kept on the same page (save VIEW) after the Save button click and showing the recent changes in the database.

ViewModel:

public class UserViewModel
{
    public string UserName { get; set; }
    public string Level { get; set; }
    public string Location { get; set; }
    public List<RoleViewModel> Roles { get; set; }
}

public class RoleViewModel
{
    public string RoleName{ get; set; }
    public bool IsSelected { get; set; }
}

View: I might be doing something very wrong in the VIEW

@model List<Project.ViewModels.UserViewModel>

@using (@Html.BeginForm("Create", "User", FormMethod.Post ,new { id = "UserPermissionForm" }))


{
<table class="table">
    <tr>
        <th>User</th>
        @for (int i = 0; i < Model[0].Roles.Count; i++)
        {
            <th>
                @Model[0].Roles[i].RoleName
            </th>
        }
    </tr>
    @for (int i = 0; i < Model.Count; i++)
    {
        <tr>
            <td>
                @Html.HiddenFor(m => m[i].UserName)
                @Model[i].UserName
            </td>
            @for (int j = 0; j < Model[i].Roles.Count; j++)
            {
                <td>
                    @Html.CheckBoxFor(m => m[i].Roles[j].IsSelected)
                </td>
            }
        </tr>
    }
</table>

<div class="form-actions">
        <button type="submit" class="btn btn-success submit" value="Save">Save changes</button>
    </div>

<script>
    $('#Submit').click(function () {
        let url = '@Url.Action("Create", "Users")'
        $.post(url, $("#UserPermissionForm"))
        });
</script>

Controller:

[HttpPost]
    public ActionResult Create(List<UserViewModel> viewModelList)
    {
        for (int i= 0; i > viewModelList.Count; i++) {
            for (int j = 0; j > viewModelList[i].Roles.Count; j++) {

                    db.UserDetails.Add(new User 
                    {
                        username = viewModelList[i].UserName,
                        level = viewModelList[i].Level,
                        location = viewModelList[i].Location,
                        role = viewModelList[i].Roles[j].RoleName,
                        Approval = "",
                        Request = "",
                        Active = "Y"
                    });
            }

            db.SaveChanges();
            return RedirectToAction("Index","Users");
        }          
        return View(viewModelList); // not right
    }

Error:

The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[Project.ViewModels.UserViewModel]', but this dictionary requires a model item of type 'Project.Models.User'.

Any guidance/help is appreciated.

EDIT1: View has been added EDIT2: Bsuiness logic added

回答1:

Here you're sending a model to the view:

return View(viewModelList);

And that model is of type List<UserViewModel>. According to the error, however, the view is expecting a model of type User. Something like this declaration on the view itself:

@model Project.Models.User

So you have two options:

  1. Change the view to accept a model of type List<UserViewModel>, making any changes as necessary within the view itself to use that new model type.
  2. Send the view a model of type Project.Models.User (which would presumably be a transformation of one element from the List<UserViewModel>?).

On a technical level either option is perfectly valid. (Though the two are mutually exclusive, it's one or the other.) It's up to you which option makes more sense for the system you're building, whether or not that view should be operating on an instance or on a list.


Edit: Your edit to the question (to include a view) seems to indicate that you may be looking at the wrong view. The view you're showing us doesn't match the error message you're showing us. Keep in mind that the two exit paths for your controller method (a redirect and a return of a view) probably invoke different views.

In any event, the core of the issue still remains. Somewhere you're providing a view with a type which is different from what it expects. You may have to do some additional debugging to determine where in your code that's happening, but ultimately the problem and potential solution remain the same as described above.