Hi,
I am trying to find out how to do client side binding on foreign keys, all the examples I have come across are for server side binding and also I have seen no reference to how to deal with different model scenarios or what your controller actions should look like.
I have been stuck about a week now and basically I have a grid that is showing permissions that references Users, Payrolls and Functions. The idea is that the grid will display the User.NetLogin, Payroll.Title and Function.Title on the grid and in the dropdowns. This is working fine, however the way I passed the data to my model as you will see below I don't think is correct and the main issue is the code controlling the create, edit, delete and save (as this uses batch edit) features. Currently only read works, all the data manipulation fails and this is what I need to get working.
The permissions model has 3 foreign keys and these are refenced in the way the MVC Student Enrolement tutorial described the enrolement model. So on the permissions table the ID of the 3 reference tables are held as well as virtual object:
e.g. public int UserID {get;set}
public virtual User User {get;set;}
On the 3 reference tables a reciprical link is held to the permissions table using:
public virtual ICollection<Permission> Permissions
I don't quite understand why this structure is used perhaps someone could exaplain? But this structure was from a tutorial on the MVC site and it worked perfectly what I have and Index view and 4 views for CRUD actions. The examples I have seen for foreign keys so far only show models with the public User User {get;set;} in them.
I am using entity framework so my permissions model is like
I have managed to get the read and custom dropdown editors working, but I can't find any code examples for the controller or the view using foreign keys like this and entity framework with kendo grid.
Currently the add action creates a javascript runtime error of 'NetLogin' is undefined. (NetLogin is a child entity of the User Object)
The save action for any delete and edit (add add) action litterally does nothing, I have traced it with firebug and it creates no errors and no actions and my knowledge of jquery is minimal to non so I couldn't trace it back.
Here is my controller:
Here is my razor view:
Any help would be really appreciated. I will make a quick example project when I get to work to assist.
Many thanks,
Andy
I am trying to find out how to do client side binding on foreign keys, all the examples I have come across are for server side binding and also I have seen no reference to how to deal with different model scenarios or what your controller actions should look like.
I have been stuck about a week now and basically I have a grid that is showing permissions that references Users, Payrolls and Functions. The idea is that the grid will display the User.NetLogin, Payroll.Title and Function.Title on the grid and in the dropdowns. This is working fine, however the way I passed the data to my model as you will see below I don't think is correct and the main issue is the code controlling the create, edit, delete and save (as this uses batch edit) features. Currently only read works, all the data manipulation fails and this is what I need to get working.
The permissions model has 3 foreign keys and these are refenced in the way the MVC Student Enrolement tutorial described the enrolement model. So on the permissions table the ID of the 3 reference tables are held as well as virtual object:
e.g. public int UserID {get;set}
public virtual User User {get;set;}
On the 3 reference tables a reciprical link is held to the permissions table using:
public virtual ICollection<Permission> Permissions
I don't quite understand why this structure is used perhaps someone could exaplain? But this structure was from a tutorial on the MVC site and it worked perfectly what I have and Index view and 4 views for CRUD actions. The examples I have seen for foreign keys so far only show models with the public User User {get;set;} in them.
I am using entity framework so my permissions model is like
public
class
User
{
public
int
UserID {
get
;
set
; }
public
string
NetLogin {
get
;
set
; }
[Required(ErrorMessage =
"Employee number is required."
)]
[Display(Name =
"Employee Number"
)]
[MaxLength(6)]
public
string
EmpNumber {
get
;
set
; }
[Required(ErrorMessage =
"First name is required."
)]
[Display(Name =
"First Name"
)]
[MaxLength(50)]
public
string
Forename {
get
;
set
; }
[Required(ErrorMessage =
"Last name is required."
)]
[Display(Name =
"Last Name"
)]
[MaxLength(50)]
public
string
Surname {
get
;
set
; }
public
bool
Active {
get
;
set
; }
public
virtual
ICollection<Permission> Permissions {
get
;
set
; }
}
public
class
Payroll
{
public
int
PayrollID {
get
;
set
; }
[Required(ErrorMessage =
"Payroll title is required."
)]
[Display(Name =
"Payroll"
)]
[MaxLength(20)]
public
string
Title {
get
;
set
; }
[Required(ErrorMessage =
"C21 description is required."
)]
[Display(Name =
"C21 Name"
)]
[MaxLength(30)]
public
string
C21Name {
get
;
set
; }
[Required(ErrorMessage =
"Server name is required."
)]
[Display(Name =
"Server Name"
)]
[MaxLength(20)]
public
string
Server {
get
;
set
; }
[Required(ErrorMessage =
"Port is required."
)]
[Display(Name =
"Port"
)]
[MaxLength(5)]
public
string
Port {
get
;
set
; }
[Required(ErrorMessage =
"Connection string is required."
)]
[Display(Name =
"Connection String"
)]
[MaxLength(200)]
public
string
Connection {
get
;
set
; }
public
virtual
ICollection<Permission> Permissions {
get
;
set
; }
}
public
class
Function
{
public
int
FunctionID {
get
;
set
; }
[Required(ErrorMessage =
"Function description is required."
)]
[Display(Name =
"Function"
)]
[MaxLength(20)]
public
string
Title {
get
;
set
; }
public
virtual
ICollection<Permission> Permissions {
get
;
set
; }
}
public
class
Permission
{
public
int
PermissionID {
get
;
set
; }
[Required(ErrorMessage =
"You must select a payroll."
)]
public
int
PayrollID {
get
;
set
; }
[Required(ErrorMessage =
"You must select a function."
)]
public
int
FunctionID {
get
;
set
; }
[Required(ErrorMessage =
"You must select a user."
)]
public
int
UserID {
get
;
set
; }
[Range(
typeof
(
double
),
"1"
,
"5"
)]
[Required(ErrorMessage =
"You must enter an access level."
)]
public
double
? Level {
get
;
set
; }
public
virtual
Payroll Payroll {
get
;
set
; }
public
virtual
Function Function {
get
;
set
; }
public
virtual
User User {
get
;
set
; }
}
I have managed to get the read and custom dropdown editors working, but I can't find any code examples for the controller or the view using foreign keys like this and entity framework with kendo grid.
Currently the add action creates a javascript runtime error of 'NetLogin' is undefined. (NetLogin is a child entity of the User Object)
The save action for any delete and edit (add add) action litterally does nothing, I have traced it with firebug and it creates no errors and no actions and my knowledge of jquery is minimal to non so I couldn't trace it back.
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)
{
var perm =
new
Permission
{
UserID = permission.UserID,
PayrollID = permission.PayrollID,
FunctionID = permission.FunctionID,
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(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 }));
/*
return Json(result.Select(p => new Permission
{
PermissionID = p.PermissionID,
UserID = p.UserID,
PayrollID = p.PayrollID,
FunctionID = p.FunctionID,
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 perms2 = 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 perms1 = 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(perms2);
}
/// <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
);
}
}
}
Here is my razor view:
@section CustomHeader {
@* kendo.common.min.css contains common CSS rules used by all Kendo themes *@
<
link
href
=
"http://cdn.kendostatic.com/2012.2.710/styles/kendo.common.min.css"
rel
=
"stylesheet"
/>
@* kendo.silver.min.css contains the "Blue Opal" Kendo theme *@
<
link
href
=
"http://cdn.kendostatic.com/2012.2.710/styles/kendo.silver.min.css"
rel
=
"stylesheet"
/>
<
script
src
=
"http://cdn.kendostatic.com/2012.2.710/js/kendo.all.min.js"
></
script
>
}
<
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 () {
var 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
>
Any help would be really appreciated. I will make a quick example project when I get to work to assist.
Many thanks,
Andy