0

I use jqGrid and the examples from Greg here helped me a lot. However I have one problem I cannot solve:

My Linq statement uses joins to collect data from three tables:

var queryDetails = (from survey in pagedQuery
                    join subproj in db.t_onlinesubproject 
                    on survey.SubPid equals subproj.datsubprojectid
                    join proj in db.t_onlineproject 
                    on subproj.datprojectid equals proj.datprojectid
                            select new
                            {
                                survey.scriptID,
                                proj.projectnumber,
                                proj.projecttitlesap,
                                subproj.subprojectname,
                                survey.Projectname,
                                survey.platform,
                                survey.Status,
                                survey.Programmer
                            }).ToList();

Whenever I try to search or order by another field than from the table survey I get an EntitySqlException, e.g. projectnumber is not an element of the current loaded schema.

When I search or order fields from the main table (scriptID, Projectname, platform, Status, Programmer), everything works fine,
projectnumber, projecttitlesap and subprojectname leads to above mentioned error.

Any idea?

Here the important parts of my sources:
View:

$(function () {
    $("#grid").jqGrid({
        url: '@Url.Action("Projects", "Json")',
        datatype: 'json',
        mtype: 'POST',
        colNames: ['id', 'Project number', 'Project title', 'Subproject title', 'Scripters Project title', 'Platform', 'Status', 'Scripter'],
        colModel: [
          { name: 'scriptID', index: 'scriptID', width: 20, align: 'right', sorttype: 'int' },
          { name: 'projectnumber', index: 'projectnumber', width: 70, align: 'right' },
          { name: 'projecttitlesap', index: 'projecttitlesap', width: 150, align: 'left' },
          { name: 'subprojectname', index: 'subprojectname', width: 150, align: 'left' },
          { name: 'Projectname', index: 'Projectname', width: 150, align: 'left' },
          { name: 'platform', index: 'platform', width: 8, align: 'center', stype: 'select', surl: '@Url.Action("platformSelect", "Json")', searchoptions: { sopt: ['eq']} },
          { name: 'Status', index: 'Status', width: 60, align: 'left', stype: 'select', surl: '@Url.Action("statusSelect", "Json")', searchoptions: { sopt: ['eq']} },
          { name: 'Programmer', index: 'Programmer', width: 100, align: 'left', stype: 'select', surl: '@Url.Action("scripterSelect", "Json")', searchoptions: { sopt: ['eq']} },
        ],
        pager: jQuery('#pager'),
        rowNum: 50,
        height: 500,
        autowidth: true,
        rowList: [5, 10, 20, 50, 100, 200],
        ignoreCase: true,
        viewrecords: true,
        imgpath: '@Url.Content("~/Content/themes/sunny/images")',
        caption: 'Projects',
        hidegrid: false,
        sortable: true,
        sortname: $.cookie("grid_index_name") ? $.cookie("grid_index_name") : "scriptID",
        sortorder: $.cookie("grid_sort_order") ? $.cookie("grid_sort_order") : "desc",
        toolbar: [false, "top"]
    });

Controller:

public JsonResult Projects(string sidx, string sord, int page, int rows, bool _search, string filters) 
{
        var serializer = new JavaScriptSerializer();
        Filters f = (!_search || string.IsNullOrEmpty(filters)) ? null : serializer.Deserialize<Filters>(filters);
        ObjectQuery<t_scripting> filteredQuery = (f == null ? db.t_scripting : f.FilterObjectSet(db.t_scripting));
        filteredQuery.MergeOption = MergeOption.NoTracking; // we don't want to update the data
        var totalRecords = filteredQuery.Count();

        var pagedQuery = filteredQuery.Skip("it." + sidx + " " + sord, "@skip", new ObjectParameter("skip", (page - 1) * rows)).Top("@limit", new ObjectParameter("limit", rows));

        // to be able to use ToString() below which is NOT exist in the LINQ to Entity
        var queryDetails = (from survey in pagedQuery
                            join subproj in db.t_onlinesubproject on survey.SubPid equals subproj.datsubprojectid
                            join proj in db.t_onlineproject on subproj.datprojectid equals proj.datprojectid
                            select new
                            {
                                survey.scriptID,
                                proj.projectnumber,
                                proj.projecttitlesap,
                                subproj.subprojectname,
                                survey.Projectname,
                                survey.platform,
                                survey.Status,
                                survey.Programmer
                            }).ToList();


var jsonData = new
        {
            total = (totalRecords + rows - 1) / rows,
            page,
            records = totalRecords,
            rows =
              (from survey in queryDetails
               select new
               {
                   id = survey.scriptID,
                   cell = new string[] { 
                  survey.scriptID.ToString(),
                  survey.projectnumber, 
                  survey.projecttitlesap,
                  survey.subprojectname,
                  survey.Projectname,
                  survey.platform != null ? (from p in platforms where (p.id == survey.platform) select p.abbreviation).Single() : String.Empty,
                  survey.Status != null ? (from s in stati where s.id == survey.Status select s.status).Single() : String.Empty,
                  survey.Programmer != null ? (from p in programmerAndCommissioner where p.id == survey.Programmer select p.forename + " " + p.surname).Single() : String.Empty
                }
               }).ToArray()
        };

        return Json(jsonData, JsonRequestBehavior.AllowGet);

}

Helpers:

    public class Filters
{
    public enum GroupOp
    {
        AND,
        OR
    }

    public enum Operations
    {
        eq, // "equal"
        ne, // "not equal"
        lt, // "less"
        le, // "less or equal"
        gt, // "greater"
        ge, // "greater or equal"
        bw, // "begins with"
        bn, // "does not begin with"
        //in, // "in"
        //ni, // "not in"
        ew, // "ends with"
        en, // "does not end with"
        cn, // "contains"
        nc  // "does not contain"
    }

    public class Rule
    {
        public string field { get; set; }
        public Operations op { get; set; }
        public string data { get; set; }
    }

    public GroupOp groupOp { get; set; }
    public List<Rule> rules { get; set; }

    private static readonly string[] FormatMapping = {
        "(it.{0} = @p{1})",                 // "eq" - equal
        "(it.{0} <> @p{1})",                // "ne" - not equal
        "(it.{0} < @p{1})",                 // "lt" - less than
        "(it.{0} <= @p{1})",                // "le" - less than or equal to
        "(it.{0} > @p{1})",                 // "gt" - greater than
        "(it.{0} >= @p{1})",                // "ge" - greater than or equal to
        "(it.{0} LIKE (@p{1}+'%'))",        // "bw" - begins with
        "(it.{0} NOT LIKE (@p{1}+'%'))",    // "bn" - does not begin with
        "(it.{0} LIKE ('%'+@p{1}))",        // "ew" - ends with
        "(it.{0} NOT LIKE ('%'+@p{1}))",    // "en" - does not end with
        "(it.{0} LIKE ('%'+@p{1}+'%'))",    // "cn" - contains
        "(it.{0} NOT LIKE ('%'+@p{1}+'%'))" //" nc" - does not contain
    };

    internal ObjectQuery<T> FilterObjectSet<T>(ObjectQuery<T> inputQuery) where T : class
    {
        if (rules.Count <= 0) return inputQuery;

        var sb = new StringBuilder();
        var objParams = new List<ObjectParameter>(rules.Count);

        foreach (Rule rule in rules)
        {
            PropertyInfo propertyInfo = typeof(T).GetProperty(rule.field);
            if (propertyInfo == null) continue; // skip wrong entries

            if (sb.Length != 0) sb.Append(groupOp);

            var iParam = objParams.Count;
            sb.AppendFormat(FormatMapping[(int)rule.op], rule.field, iParam);

            ObjectParameter param;

            //nullable workaround
            string type = "";
            if (propertyInfo.PropertyType.FullName.StartsWith("System.Nullable"))
            {
                Match m = Regex.Match(propertyInfo.PropertyType.FullName, @"\[\[(.+?),");
                if (m.Groups.Count < 2) type = propertyInfo.PropertyType.FullName;
                type = m.Groups[1].ToString();
            }
            else type = propertyInfo.PropertyType.FullName;
            //end nullable workaround
            //switch (propertyInfo.PropertyType.FullName)
            switch (type)
            {
                case "System.Int32":  // int
                    param = new ObjectParameter("p" + iParam, Int32.Parse(rule.data));
                    break;
                case "System.Int64":  // bigint
                    param = new ObjectParameter("p" + iParam, Int64.Parse(rule.data));
                    break;
                case "System.Int16":  // smallint
                    param = new ObjectParameter("p" + iParam, Int16.Parse(rule.data));
                    break;
                case "System.SByte":  // tinyint
                    param = new ObjectParameter("p" + iParam, SByte.Parse(rule.data));
                    break;
                case "System.Single": // Edm.Single, in SQL: float
                    param = new ObjectParameter("p" + iParam, Single.Parse(rule.data));
                    break;
                case "System.Double": // float(53), double precision
                    param = new ObjectParameter("p" + iParam, Double.Parse(rule.data));
                    break;
                case "System.Boolean": // Edm.Boolean, in SQL: bit
                    param = new ObjectParameter("p" + iParam,
                        String.Compare(rule.data, "1", StringComparison.Ordinal) == 0 ||
                        String.Compare(rule.data, "yes", StringComparison.OrdinalIgnoreCase) == 0 ||
                        String.Compare(rule.data, "true", StringComparison.OrdinalIgnoreCase) == 0 ?
                        true :
                        false);
                    break;
                default:
                    // TO DO: Extend to other data types
                    // binary, date, datetimeoffset,
                    // decimal, numeric,
                    // money, smallmoney
                    // and so on
                    param = new ObjectParameter("p" + iParam, rule.data);
                    break;
            }
            objParams.Add(param);
        }

        ObjectQuery<T> filteredQuery = inputQuery.Where(sb.ToString());
        foreach (var objParam in objParams)
            filteredQuery.Parameters.Add(objParam);

        return filteredQuery;
    }
}
Community
  • 1
  • 1
Oliver Kötter
  • 1,006
  • 11
  • 29

1 Answers1

0

You should indeed order by proj.projectnumber, proj.projecttitlesap and subproj.subprojectname. without prefixes (proj and subproj) you will get that error, because you start joining from survey, survey.[fieldname] and [fieldname] are the same, but proj.[fieldname] and subproj.[fieldname] are not equal. try to find a way in jqGrid to specify sorting expression like SortExpression in asp.net GridView.

Uchiha_Sasuke
  • 309
  • 2
  • 9
  • see this example [link](http://haacked.com/archive/2009/04/13/using-jquery-grid-with-asp.net-mvc.aspx), It's not completely related to your issue, but has a better and more clear sample for jqGrid, you may find something useful there;) – Uchiha_Sasuke Jan 21 '13 at 16:15
  • Thanks, but this is useless as my solution is based on this and this example does not use joins. – Oliver Kötter Jan 21 '13 at 16:21
  • `Skip("it." + sidx + " " + sord...` is the problem, what is `it` refering to? you should not page query before joining it, because first you are selecting a table, then paging and ordering by a field that do not exist in that table and after that you are joining it with the table which owns that field, sequence of works are wrong. My english is bad, i hope you have understood my sentence. – Uchiha_Sasuke Jan 21 '13 at 16:30
  • I mean before using `Skip` and `Take` you should join. – Uchiha_Sasuke Jan 21 '13 at 16:33
  • ok, so first I do var s = (from ... join ... join ... select new { }).toList(); and then? Code example would help, because this way my old source won't work anymore, ObjectQuery filteredQuery does not work this way. – Oliver Kötter Jan 22 '13 at 16:39