Requested unknown parameter 'tblIngredient.IngredientName' for row 0, column 0
Requested unknown parameter 'tblIngredient.IngredientName' for row 0, column 0
All was going fine. I was doing a Left Join and displaying data from 3 related tables in MVC...until I upgrade from ASP.NET CORE 2.2 to 3.0. Then I get this error.
_Uncaught Error: DataTables warning: table id=recipeIngredientTable - Requested unknown parameter 'tblIngredient.IngredientName' for row 0, column 0. For more information about this error, please see http://datatables.net/tn/4_
Yes I looked at the link in that error. I do not see any typos in the unknown string parameter. The field names match my SQL Server database table fields, all of them. I mean it worked already in .NET Core 2.2. Also from the breakpoints in the server-side C# code I notice the values are being retrieved successfully and the database is being seeded correctly. Except the table is not rendering in the front-end. I can only wonder why.
Yes I am creating the database with EF Core and know it is not supported with Editor libraries. All good.
index.cshtml
@model DTEditorLeftJoinSample.Models.RecipeIngredient
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<table id="recipeIngredientTable">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Recipe)
</th>
<th>
@Html.DisplayNameFor(model => model.Ingredient)
</th>
<th>
@Html.DisplayNameFor(model => model.Quantity)
</th>
<th></th>
</tr>
</thead>
<tbody></tbody>
</table>
@section scripts{
<script>
$.fn.dataTable.ext.errMode = 'throw';
function renderDT_RowId(data) {
return data.replace('row_', '');
};
var oTable = $('#recipeIngredientTable').DataTable({
"ajax": {
type: "POST",
"url": "@Url.Action("LeftJoinRecipesAndIngredientsOntoRecipeIngredient")",
"dataSrc": function (result) {
return result.data;
}
},
"columns": [
{ "data": "tblIngredient.IngredientName"},
{ "data": "tblRecipe.Description"},
{ "data": "tblRecipeIngredient.Quantity" },
{
"data": null,
"render": function (value) {
return '<a href="/RecipeIngredients/Details/' + renderDT_RowId(value.DT_RowId) + '"button type="button" class="btn btn-primary btn-block">Details</a> <br> '
+ '<a href="/RecipeIngredients/Edit/' + renderDT_RowId(value.DT_RowId) + '"button type="button" class="btn btn-info btn-block">Edit </a> <br> '
+ '<a href="/RecipeIngredients/Delete/' + renderDT_RowId(value.DT_RowId) + '"button type="button" class="btn btn-primary btn-block">Delete</a>';
}
}
]
});
</script>
}
RecipeIngredientsController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using DTEditorLeftJoinSample.Data;
using DTEditorLeftJoinSample.Models;
using DataTables;
using Microsoft.Extensions.Configuration;
namespace DTEditorLeftJoinSample.Controllers
{
public class RecipeIngredientsController : Controller
{
private readonly CookingContext _context;
private readonly IConfiguration _config;
public RecipeIngredientsController(CookingContext context, IConfiguration config)
{
_context = context;
_config = config;
}
// GET: RecipeIngredients
public IActionResult Index()
{
return View();
}
public IActionResult LeftJoinRecipesAndIngredientsOntoRecipeIngredient()
{
//DECLARE database connection.
string connectionString = _config.GetConnectionString("DefaultConnection");
//CREATE debatable instance.
using (var db = new Database("sqlserver", connectionString))
{
//CREATE Editor instance with starting table.
var response = new Editor(db, "tblRecipeIngredient")
.Field(new Field("tblRecipeIngredient.Quantity"))
.Field(new Field("tblRecipe.Description"))
.Field(new Field("tblIngredient.IngredientName"))
//JOIN from tblIngredient column RecipeID linked from tblRecipe column ID
//and IngredientID linked from tblUser column ID.
.LeftJoin("tblRecipe ", " tblRecipe.ID ", "=", " tblRecipeIngredient.RecipeID")
.LeftJoin("tblIngredient ", " tblIngredient.ID ", "=", " tblRecipeIngredient.IngredientID")
.Process(HttpContext.Request)
.Data();
return Json(response);
}
}
}
}
Ingredient.cs
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DTEditorLeftJoinSample.Models
{
public class Ingredient
{
public int ID { get; set; }
[Display(Name = "Ingredient Name")]
public string IngredientName { get; set; }
public ICollection<RecipeIngredient> RecipeIngredient { get; set; }
}
}
Recipe.cs
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DTEditorLeftJoinSample.Models
{
public class Recipe
{
public int ID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Direction { get; set; }
public ICollection<RecipeIngredient> RecipeIngredient { get; set; }
}
}
RecipeIngredient.cs
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DTEditorLeftJoinSample.Models
{
public class RecipeIngredient
{
public int ID { get; set; }
[Display(Name = "Recipe ID")]
public int RecipeID { get; set; }
[Display(Name = "Ingredient ID")]
public int IngredientID { get; set; }
public int Quantity { get; set; }
public Recipe Recipe { get; set; }
public Ingredient Ingredient { get; set; }
}
}
CookingContext.cs
using DTEditorLeftJoinSample.Models;
using Microsoft.EntityFrameworkCore;
namespace DTEditorLeftJoinSample.Data
{
public class CookingContext : DbContext
{
public CookingContext(DbContextOptions<CookingContext> options) : base(options)
{
}
public DbSet<Recipe> Recipe { get; set; }
public DbSet<Ingredient> Ingredient { get; set; }
public DbSet<RecipeIngredient> RecipeIngredient { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Recipe>().ToTable("tblRecipe");
modelBuilder.Entity<Ingredient>().ToTable("tblIngredient");
modelBuilder.Entity<RecipeIngredient>().ToTable("tblRecipeIngredient ");
}
}
}
Replies
Start with looking at the JSON response using the browser's network inspector. This technote will give some steps.
You have this:
If your row data is an array in the
data
object then you don't need this as that is the default location where Datatables will look for the data as described here.If you still need help please post an example of your JSON response to include the start (the
data
object) and a few rows of your data.Kevin
Hi @kthorngren
Seems it is returning data all the way from the backend even even in the JSON response.
Here is the preview as it looks neater.
And here is the actual JSON response
The response has this for example:
You defined it as:
Its case sensitive so it should be
ingredientName
instead ofIngredientName
, like this:Same with the other
columns.data
options you have the wrong case.Kevin
Thank you so much @kthorngren it works. Also had to change the value DT_RowId to dT_RowId which totally worked.
The thing is I never had such case sensitivity when I used DataTables in ASP .NET Core 2.2. Maybe it has changed in future frameworks.
The Javascript side of things has always been case sensitive. Possibly things have changed a little on the server-side (although not intentionally on our part if so!).
Allan
@allan
I think you're right about changes on the server side. Because now that I've upgraded my app to .NET 5.0 guess what, I have to make the first letter of all fields now in upper case in order for the application to run.
Even had to install newtonsoft manually so I don't get **Uncaught TypeError: Cannot read property 'length' of undefined. **
I'm sure it's a problem on the server. Anyway thanks for your help guys. I actually made a whole blog about how to integrate DataTables Editor into ASP.NET 5.0 which couldn't have been done without your help. https://layersofabstraction.github.io/DTLeftJoins2.html
Very nice! Is it okay if I link to your article from our news feed on the front page?
Allan
@allan
I would be delighted in seeing that. Thanks.
First one of 2021 - many thanks!
Allan