This is a migrated thread and some comments may be shown as answers.

How do I display virtual model entities as grid fields?

1 Answer 135 Views
Grid
This is a migrated thread and some comments may be shown as answers.
andrew
Top achievements
Rank 1
andrew asked on 19 Jul 2012, 04:31 PM
Hi,

I am using MVC 4, reposistory pattern and EF 4.3, I am trying to display virtual objects that are in my models.

For example in a products model you may have:

public int ProductID {get;set;}
public string Title {get;set;}
public int CategoryID {get;set;}
public double Price {get;set;}
public bool Discontinued {get;set;}
public virtual Category Category {get;set;}

The the category model may be:

public int CategoryID {get;set;}
public string Name {get;set;}


So in my properties CRUD grid I want the user to see the Products.Category.Name rather than the Products.CategoryID.

I also want a dropdown for users to select the Category name from and this would update the products model with the CategoryID.

The problem I get when I reference Products.Category.Name is that the grid displays "UnDefined" in the category column.

Please can someone show me both the controller actions and the view as an example of how this should be achieved.

I am using Razor views.

Many thanks,

Andy

1 Answer, 1 is accepted

Sort by
0
andrew
Top achievements
Rank 1
answered on 20 Jul 2012, 01:33 PM
I have managed to create custom helpers and populate them, I have also managed to populate the grid with my data, however I cannot save any CREATE, DESTROY or EDIT actions. I believe this is because I need to translate the dynamic proxy fields back to the entity model.

The entity model I am working with is called "Permissions", within permissions there are "User", "Payroll" and "Function" dynamic proxies.

I found that by passing the "Permissions" repository to the grid with Ajax, my UserName, PayrollTitle and FunctionTitle fields were "Undefined".

I played around for a while and eventually managed to change my ajax query as follows to pass in all the required information.
[HttpPost]
public ActionResult Read()
{
var perms = unitOfWork.PermissionRepository.Get()
.Select(r => new { PermissionID = r.PermissionID, UserID = r.UserID, PayrollID = r.PayrollID, FunctionID = r.FunctionID, Level = r.Level, NetLogin = r.User.NetLogin, PayrollTitle = r.Payroll.Title, FunctionTitle = r.Function.Title });
/* var perms = unitOfWork.PermissionRepository.Get()
// Use a view model to avoid serializing internal Entity Framework properties as JSON
.Select(p => new Permission
{
PermissionID = p.PermissionID,
UserID = p.UserID,
PayrollID = p.PayrollID,
FunctionID = p.FunctionID,
Level = p.Level
}).ToList();*/
return Json(perms);
}

The commented out code is the originally query to pass data to the view.

The problem was that I could not access "Permisions.User.NetLogin", "Permissions.Payroll.Title" and "Permission.Function.Title".

This got the permissions data in to the view and I made some custom editors which can be seen in my view code below:
@section CustomHeader {
    @* kendo.common.min.css contains common CSS rules used by all Kendo themes *@
    @* kendo.silver.min.css contains the "Blue Opal" Kendo theme *@
}
<h2>Permissions</h2>
<h3>Page Size: <div id="comboBox"></div></h3>
<script>
    $("#comboBox").kendoComboBox({
        dataTextField: "text",
        dataValueField: "value",
        dataSource: [
            { text: 10 },
            { text: 25 },
            { text: 50 },
            { text: 100 },
            { text: 500 }
        ],
        change: function (e) {
            var grid = $("#grid").data("kendoGrid");
            grid.dataSource.pageSize(this.value());
        }
    });
</script>
@* The DIV where the Kendo grid will be initialized *@
<div id="grid"></div>
<script>
 
$(document).ready(function () {
    dataSource = new kendo.data.DataSource({
    transport: {
        create: {
            url: "@Url.Action("Create", "Permission")", //specify the URL which should create new records. This is the Create method of the HomeController.
            type: "POST" //use HTTP POST request as the default GET is not allowed for ASMX
        },
        read: {
            url: "@Url.Action("Read", "Permission")", //specify the URL which should return the records. This is the Read method of the HomeController.
            type: "POST", //use HTTP POST request as by default GET is not allowed by ASP.NET MVC
        },
        update: {
            url:"@Url.Action("Update", "Permission")", //specify the URL which should update the records. This is the Update method of the HomeController.
            type: "POST" //use HTTP POST request as by default GET is not allowed by ASP.NET MVC
        },
        destroy: {
            url: "@Url.Action("Destroy", "Permission")", //specify the URL which should destroy the records. This is the Destroy method of the HomeController.
            type: "POST" //use HTTP POST request as by default GET is not allowed by ASP.NET MVC
        },
        parameterMap: function(data, operation) {
            if (operation != "read") {
                // post the products so the ASP.NET DefaultModelBinder will understand them:
 
                var result = {};
 
                for (var i = 0; i < data.models.length; i++) {
                    var perm = data.models[i];
 
                    for (var member in perm) {
                        result["perms[" + i + "]." + member] = perm[member];
                    }
                }
 
                return result;
            }
        },
        batch: true, // enable batch editing - changes will be saved when the user clicks the "Save changes" button
        pageSize: 20,
        schema: {
            model: { // define the model of the data source. Required for validation and property types.
                id: "PermissionID",
                fields: {
                    PermissionID: { editable: false, nullable: true },
                    NetLogin: "User",
                    PayrollTitle: "Payroll",
                    FunctionTitle: "Function",
                    Level: { type: "number", validation: { required: true, min: 1} }
                }
            }
        }
    }});                     
 
    $("#grid").kendoGrid({
        dataSource: dataSource,
        pageable: true,
        height: 425,
        sortable: true,
        filterable: true,
        groupable: true,
        resizable: true,
        reorderable: true,
        toolbar: ["create", "save", "cancel"], // specify toolbar commands
        columns: [
            { field: "NetLogin", width: "70px", editor: userDropDownEditor },
            { field: "PayrollTitle", width: "70px", editor: payrollDropDownEditor },
            { field: "FunctionTitle", width: "70px", editor: functionDropDownEditor },
            { field: "Level", width: "70px" },
            { command: "destroy", title: "Delete", width: "60px", groupable: false, filterable: false }],
        editable: true // enable editing
    });
 
});
 
function userDropDownEditor(container, options) {
    $('<input data-text-field="NetLogin" data-value-field="NetLogin" data-bind="value:' + options.field + '"/>')
        .appendTo(container)
        .kendoDropDownList({
            autoBind: false,
            dataSource: {
                transport: {
                    read: {
                        url: "@Url.Action("Read", "User")", //specify the URL which should return the records. This is the Read method of the HomeController.
                        type: "POST" //use HTTP POST request as by default GET is not allowed by ASP.NET MVC
                    }
                }
            }
        });
}
 
function payrollDropDownEditor(container, options) {
    $('<input data-text-field="Title" data-value-field="Title" data-bind="value:' + options.field + '"/>')
        .appendTo(container)
        .kendoDropDownList({
            autoBind: false,
            dataSource: {
                transport: {
                    read: {
                        url: "@Url.Action("Read", "Payroll")", //specify the URL which should return the records. This is the Read method of the HomeController.
                        type: "POST" //use HTTP POST request as by default GET is not allowed by ASP.NET MVC
                    }
                }
            }
        });
}
 
function functionDropDownEditor(container, options) {
    $('<input data-text-field="Title" data-value-field="Title" data-bind="value:' + options.field + '"/>')
        .appendTo(container)
        .kendoDropDownList({
            autoBind: false,
            dataSource: {
                transport: {
                    read: {
                        url: "@Url.Action("Read", "Function")", //specify the URL which should return the records. This is the Read method of the HomeController.
                        type: "POST" //use HTTP POST request as by default GET is not allowed by ASP.NET MVC
                    }
                }
            }
        });
}
 
</script>

This covers the Read() actions and custom editors, however I need some help in how I translate both the controller code and possibly the view code (I'm not sure?) so that the UserID, PayrollID and FunctionID are passed back to the "Permissions" Model.

Please can someone help?

Andy

P.S.

Here is my controller:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using PayPlate.Models;
using PayPlate.DAL;
using PagedList;
 
namespace PayPlate.Controllers
{
    public class PermissionController : Controller
    {
        UnitOfWork unitOfWork = new UnitOfWork();
 
        public ActionResult Index()
        {
            return View();
        }
 
        /// <summary>
        /// Creates new products by inserting the data posted by the Kendo Grid in the database.
        /// </summary>
        /// <param name="products">The products created by the user.</param>
        /// <returns>The inserted products so the Kendo Grid is aware of the database generated ProductID</returns>
        [HttpPost]
        public ActionResult Create(IEnumerable<Permission> perms)
        {
            var result = new List<Permission>();
 
            //Iterate all created products which are posted by the Kendo Grid
            foreach (var permission in perms)
            {
                // Create a new Product entity and set its properties from productViewModel
                var perm = new Permission
                {
                    User = permission.User,
                    Payroll = permission.Payroll,
                    Function = permission.Function,
                    Level = permission.Level                 
                };
 
                // store the product in the result
                result.Add(perm);
 
                // Add the entity
                unitOfWork.PermissionRepository.Insert(perm);
            }
 
            // Insert all created products to the database
            unitOfWork.Save();
 
            // Return the inserted products - the Kendo Grid needs their ProductID which is generated by SQL server during insertion
 
            return Json(result.Select(p => new Permission
            {
                PermissionID = p.PermissionID,
                User = p.User,
                Payroll = p.Payroll,
                Function = p.Function,
                Level = p.Level 
            })
            .ToList());
        }
 
        /// <summary>
        /// Reads the available products to provide data for the Kendo Grid
        /// </summary>
        /// <returns>All available products as JSON</returns>
        [HttpPost]
        public ActionResult Read()
        {
            var perms = unitOfWork.PermissionRepository.Get()
                .Select(r => new { PermissionID = r.PermissionID, UserID = r.UserID, PayrollID = r.PayrollID, FunctionID = r.FunctionID, Level = r.Level, NetLogin = r.User.NetLogin, PayrollTitle = r.Payroll.Title, FunctionTitle = r.Function.Title });
 
           /* var perms = unitOfWork.PermissionRepository.Get()
                // Use a view model to avoid serializing internal Entity Framework properties as JSON
                .Select(p => new Permission
                {
                    PermissionID = p.PermissionID,
                    UserID = p.UserID,
                    PayrollID = p.PayrollID,
                    FunctionID = p.FunctionID,
                    Level = p.Level
                }).ToList();*/
 
            return Json(perms);
        }
 
        /// <summary>
        /// Updates existing products by updating the database with the data posted by the Kendo Grid.
        /// </summary>
        /// <param name="products">The products updated by the user</param>
        [HttpPost]
        public ActionResult Update(IEnumerable<Permission> perms)
        {
            //Iterate all created products which are posted by the Kendo Grid
            foreach (var permission in perms)
            {
                // Attach the entity
                unitOfWork.PermissionRepository.Update(permission);
            }
 
            // Save all updated products to the database
            unitOfWork.Save();
 
            //Return emtpy result
            return Json(null);
        }
 
        /// <summary>
        /// Destroys existing products by deleting them from the database.
        /// </summary>
        /// <param name="products">The products deleted by the user</param>
        [HttpPost]
        public ActionResult Destroy(IEnumerable<Permission> perms)
        {
            //Iterate all destroyed products which are posted by the Kendo Grid
            foreach (var permission in perms)
            {
                // Delete the entity
                unitOfWork.PermissionRepository.Delete(permission);
            }
 
            // Delete the products from the database
            unitOfWork.Save();
 
            //Return emtpy result
            return Json(null);
        }
    }
}
Tags
Grid
Asked by
andrew
Top achievements
Rank 1
Answers by
andrew
Top achievements
Rank 1
Share this question
or