Search code examples
linqjoinasp.net-mvc-5datacontextmvcgrid

MVC5 MVCGRID Linq multiples tables


Im working with ASPNET MVC5 and i just Followed this tutorial : http://www.c-sharpcorner.com/UploadFile/4d9083/creating-simple-grid-in-mvc-using-grid-mvc/ and it works fine. I now want to update my HomeController with 2 tables (Users & Roles), Note : My Datacontext contains 2 tables (Users & Roles)

HomeController.cs

 public ActionResult Details()
        {
            DataClassesUserDataContext db = new DataClassesUserDataContext();
            var SchemeList = from d in db.AspNetUsers
                             join i in db.AspNetUserRoles
                               on d.Id equals i.UserId
                             select new { AspNetUsers = d, AspNetUserRole = i };
            return View(SchemeList);
        }

I return good my results

Now in my View :

My Details.cshtml Is the probleme here ? can i call shanuMVCUserRoles.DB.AspNetUser & AspNetUserRoles ???

@model IEnumerable <shanuMVCUserRoles.DB.AspNetUser>
// possible to add other models here ? @model IEnumerable <shanuMVCUserRoles.DB.AspNetUserRole >


  >  <div
    > class="code-cut">
    >     @Html.Grid(Model).Columns(columns => {
    >     columns.Add(c => c.UserName).Titled("UserName").Filterable(true);
    >     columns.Add(c => c.Id).Titled("ID").Filterable(true);
    >     columns.Add(c => c.PasswordHash).Titled("PasswordHash").Filterable(true);
    >     columns.Add(c => c.Email).Titled("Email").Filterable(true);
    >     columns.Add(c => c.AccessFailedCount).Titled("AccessFailedCount").Filterable(true);
    >     columns.Add(c => c.PhoneNumber).Titled("PhoneNumber").Filterable(true);
    >     columns.Add()
    >     .Encoded(false)
    >     .Sanitized(false)
    >     .SetWidth(30)
    >     .RenderValueAs(o => Html.ActionLink("Edit", "Edit", new { id = o.Id })); }).WithPaging(10).Sortable(true) </div>

i have the following error : The model item passed into the dictionary is of type 'System.Data.Linq.DataQuery1[<>f__AnonymousType42[shanuMVCUserRoles.DB.AspNetUser,shanuMVCUserRoles.DB.AspNetUserRole]]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[shanuMVCUserRoles.DB.AspNetUser]'.


Solution

  • you could workaround the problem by putting your AspNetUserRoles collection into ViewBag. This link shows this solution among others: http://www.codeproject.com/Articles/687061/Multiple-Models-in-a-View-in-ASP-NET-MVC-MVC

    Personally, I consider the Model as a kind of contract between my Controller and my View, so I do not like putting business information outside the Model. For example, it would be ok to store a string to format DateTimes into the ViewBag. But if I want a Controller and a View to manage Users and Roles, I want it to be clear for me and for anybody else reading the code, which can happen today, tomorrow or in ten years.

    So in this case I would create a Model class:

    namespace WebApplication1.Models
    {
        public class UsersAndRolesModel
        {
            public IList<shanuMVCUserRoles.DB.AspNetUser> Users { get; set; }
            public IList<shanuMVCUserRoles.DB.AspNetRole> Roles { get; set; }
        }
    }
    

    I would create it and populate it in my Controller. Then in my View I would declare:

    @model WebApplication1.Models.UsersAndRolesModel
    

    and finally my grids:

    @Html.Grid(Model.Users).Columns(columns => { // and so on...
    
    @Html.Grid(Model.Roles).Columns(columns => { // and so on...
    

    I hope this helps.

    Editing: Hi David, it depends on what you actually want to do: do you want a View showing two tables, one for all the users and one for all the roles? In this case, a first implementation could (but should not) be:

        public ActionResult Details()
        {
            UsersAndRolesModel model = new UsersAndRolesModel();
            DataClassesUserDataContext db = new DataClassesUserDataContext();
            model.Users = db.AspNetUsers.ToList();
            model.Roles = db.AspNetUserRoles.ToList();
            return View(model);
        }
    

    I wrote should not be because DataClassesUserDataContext must be disposed after usage. So what you really should do is:

    public class HomeController : Controller
    {
        private DataClassesUserDataContext db = new DataClassesUserDataContext();
    
        public ActionResult Details()
        {
            UsersAndRolesModel model = new UsersAndRolesModel();
            model.Users = db.AspNetUsers.ToList();
            model.Roles = db.AspNetUserRoles.ToList();
            return View(model);
        }
    
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }
    
    }