/// <summary> /// Validate the MJoin fields submitted /// </summary> /// <param name="response">DataTables response object to record the errors</param> /// <param name="editor">Host Editor instance</param> /// <param name="data">Data submitted by the client</param> internal void Validate(DtResponse response, Editor editor, Dictionary <string, object> data) { if (!_set || !data.ContainsKey(_name)) { return; } _Prepare(editor); var list = (Dictionary <string, object>)data[_name]; foreach (var dataSet in list.Select(item => item.Value as Dictionary <string, object>)) { foreach (var field in _fields) { var validation = field.Validate(dataSet, editor); if (validation != null) { response.fieldErrors.Add(new DtResponse.FieldError { name = _name + "[]." + field.Name(), status = validation }); } } } }
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Public methods */ /// <summary> /// Merge a response object into this one to create a single combined /// object. Generally parameters that are defined in the object passed /// in as a parameter will overwrite the parameters in this object if /// the are defined. /// </summary> /// <param name="b">Response object to merge in</param> /// <returns>Self for chaining</returns> public DtResponse Merge(DtResponse b) { if (b.draw != null) { this.draw = b.draw; } if (b.data.Count() != 0) { this.data = b.data; } if (b.error != null) { this.error = b.error; } if (b.fieldErrors != null) { this.fieldErrors = b.fieldErrors; } if (b.id != null) { this.id = b.id; } if (b.recordsTotal != null) { this.recordsTotal = b.recordsTotal; } if (b.recordsFiltered != null) { this.recordsFiltered = b.recordsFiltered; } if (b.options.Count() != 0) { this.options = b.options; } if (b.searchPanes != null && b.searchPanes.options != null && b.searchPanes.options.Count() != 0) { this.searchPanes.options = b.searchPanes.options; } else if (b.searchPanes == null) { this.searchPanes = null; } if (b.files.Count() != 0) { this.files = b.files; } return(this); }
/// <summary> /// Validate the MJoin fields submitted /// </summary> /// <param name="response">DataTables response object to record the errors</param> /// <param name="editor">Host Editor instance</param> /// <param name="data">Data submitted by the client</param> internal void Validate(DtResponse response, Editor editor, Dictionary <string, object> data, DtRequest.RequestTypes action) { if (!_set) { return; } _Prepare(editor); var list = data.ContainsKey(_name) ? (Dictionary <string, object>)data[_name] : new Dictionary <string, object>(); // Grouped validation for (var i = 0; i < _validators.Count(); i++) { var res = _validators[i](editor, action, list); if (res != "" && res != null) { response.fieldErrors.Add(new DtResponse.FieldError { name = _validatorFields[i], status = res }); } } // Field validation foreach (var dataSet in list.Select(item => item.Value as Dictionary <string, object>)) { foreach (var field in _fields) { var validation = field.Validate(dataSet, editor); if (validation != null) { response.fieldErrors.Add(new DtResponse.FieldError { name = _name + "[]." + field.Name(), status = validation }); } } } }
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Internal methods */ /// <summary> /// Data "get" request - get the joined data /// </summary> /// <param name="editor">Host Editor instance</param> /// <param name="response">DataTables reponse object for where the data /// should be written to</param> internal void Data(Editor editor, DtResponse response) { if (!response.data.Any()) { return; } _Prepare(editor); // If the Editor primary key is join key, then it is read automatically // and into Editor's primary key store var pkeyIsJoin = _hostField == editor.Pkey() || _hostField == editor.Table()[0]; // Check that the joining field is available var joinFieldName = _hostField.Split('.')[1]; if (!pkeyIsJoin && !response.data[0].ContainsKey(joinFieldName)) { throw new Exception( "Join was performed on the field '" + _hostField + "' which was not " + "included in the Editor field list. The join field must be " + "included as a regular field in the Editor instance." ); } // Build the basic query var query = editor.Db() .Query("select") .Get(_hostField + " as dteditor_pkey") .Table(editor.Table()[0]); if (Order() != null) { query.Order(Order()); } _ApplyWhere(query); foreach (var field in _fields.Where(field => field.Apply("get") && field.GetValue() == null)) { if (field.DbField().IndexOf('.') == -1) { query.Get(_table + "." + field.DbField() + " as " + field.DbField()); } else { query.Get(field.DbField()); } } // Create the joins if (_linkTable != null) { query.Join(_linkTable, _hostField + " = " + _linkHostField); query.Join(_table, _childField + " = " + _linkChildField); } else { query.Join(_table, _childField + " = " + _hostField); } var result = query.Exec(); if (result.Count() == 0) { return; } // Map the data to the primary key for fast look up var join = new Dictionary <string, List <object> >(); Dictionary <string, object> row; while ((row = result.Fetch()) != null) { var inner = new Dictionary <string, object>(); foreach (var field in _fields.Where(field => field.Apply("get"))) { field.Write(inner, row); } var lookup = row["dteditor_pkey"].ToString(); if (!join.ContainsKey(lookup)) { join.Add(lookup, new List <object>()); } join[lookup].Add(inner); } // Loop over the data and do a join based on the data available foreach (var data in response.data) { var linkField = pkeyIsJoin ? (data["DT_RowId"].ToString()).Replace(editor.IdPrefix(), "") : data[joinFieldName].ToString(); data.Add(_name, join.ContainsKey(linkField) ? join[linkField] : new List <object>() ); } // Field options foreach (var field in _fields) { var opts = field.OptionsExec(editor.Db()); if (opts != null) { response.options.Add(_name + "[]." + field.Name(), opts); } } }
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Internal methods */ /// <summary> /// Data "get" request - get the joined data /// </summary> /// <param name="editor">Host Editor instance</param> /// <param name="response">DataTables response object for where the data /// should be written to</param> internal void Data(Editor editor, DtResponse response) { _Prepare(editor); if (response.data.Count() != 0) { // This is something that will likely come in a future version, but it // is a relatively low use feature. Please get in touch if this is // something you require. var pkeyA = editor.Pkey(); if (pkeyA.Length > 1) { throw new Exception("MJoin is not currently supported with a compound primary key for the main table."); } // If the Editor primary key is join key, then it is read automatically // and into Editor's primary key store var pkeyIsJoin = _hostField == pkeyA[0] || _hostField == editor.Table()[0]; // Build the basic query var query = editor.Db() .Query("select") .Distinct(true) .Get(_hostField + " as dteditor_pkey") .Table(editor.Table()[0]); if (Order() != null) { query.Order(Order()); } _ApplyWhere(query); foreach (var field in _fields.Where(field => field.Apply("get") && field.GetValue() == null)) { if (field.DbField().IndexOf('.') == -1) { query.Get(_table + "." + field.DbField() + " as " + field.DbField()); } else { query.Get(field.DbField()); } } // Create the joins if (_linkTable != null) { query.Join(_linkTable, _hostField + " = " + _linkHostField); query.Join(_table, _childField + " = " + _linkChildField); } else { query.Join(_table, _childField + " = " + _hostField); } var readField = ""; var joinFieldName = _hostField.Split('.')[1]; if (NestedData.InData(_hostField, response.data[0])) { readField = _hostField; } else if (NestedData.InData(joinFieldName, response.data[0])) { readField = joinFieldName; } else if (!pkeyIsJoin) { throw new Exception( "Join was performed on the field '" + _hostField + "' which was not " + "included in the Editor field list. The join field must be " + "included as a regular field in the Editor instance." ); } // There appears to be a bug in the MySQL drivers for .NETCore whereby if there is // only one result in the original data set, then it can only read one result into // the new data set when using WHERE IN. Any other number of rows is fine. Tried // different versions of the server and driver but to no avail, so this is a workaround. if (editor.Db().DbType() != "mysql" || response.data.Count != 1) { // Get list of pkey values and apply as a WHERE IN condition // This is primarily useful in server-side processing mode and when filtering // the table as it means only a sub-set will be selected // This is only applied for "sensible" data sets. It will just complicate // matters for really large data sets: // https://stackoverflow.com/questions/21178390/in-clause-limitation-in-sql-server if (response.data.Count < 1000) { var whereIn = new List <object>(); foreach (var data in response.data) { whereIn.Add(pkeyIsJoin ? (data["DT_RowId"].ToString()).Replace(editor.IdPrefix(), "") : NestedData.ReadProp(readField, data).ToString() ); } query.WhereIn(_hostField, whereIn); } } var result = query.Exec(); // Map the data to the primary key for fast look up var join = new Dictionary <string, List <Dictionary <string, object> > >(); Dictionary <string, object> row; while ((row = result.Fetch()) != null) { var inner = new Dictionary <string, object>(); foreach (var field in _fields.Where(field => field.Apply("get"))) { field.Write(inner, row); } var lookup = row["dteditor_pkey"].ToString(); if (!join.ContainsKey(lookup)) { join.Add(lookup, new List <Dictionary <string, object> >()); } join[lookup].Add(inner); } // Loop over the data and do a join based on the data available foreach (var data in response.data) { var linkField = pkeyIsJoin ? (data["DT_RowId"].ToString()).Replace(editor.IdPrefix(), "") : NestedData.ReadProp(readField, data).ToString(); data.Add(_name, join.ContainsKey(linkField) ? join[linkField] : new List <Dictionary <string, object> >() ); } } // Field options foreach (var field in _fields) { var opts = field.OptionsExec(editor.Db()); if (opts != null) { response.options.Add(_name + "[]." + field.Name(), opts); } } }
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Internal methods */ /// <summary> /// Data "get" request - get the joined data /// </summary> /// <param name="editor">Host Editor instance</param> /// <param name="response">DataTables reponse object for where the data /// should be written to</param> internal void Data(Editor editor, DtResponse response) { _Prepare(editor); // This is something that will likely come in a future version, but it // is a relatively low use feature. Please get in touch if this is // something you require. var pkeyA = editor.Pkey(); if (pkeyA.Length > 1) { throw new Exception("MJoin is not currently supported with a compound primary key for the main table."); } // If the Editor primary key is join key, then it is read automatically // and into Editor's primary key store var pkeyIsJoin = _hostField == pkeyA[0] || _hostField == editor.Table()[0]; // Build the basic query var query = editor.Db() .Query("select") .Distinct(true) .Get(_hostField + " as dteditor_pkey") .Table(editor.Table()[0]); if (Order() != null) { query.Order(Order()); } _ApplyWhere(query); foreach (var field in _fields.Where(field => field.Apply("get") && field.GetValue() == null)) { if (field.DbField().IndexOf('.') == -1) { query.Get(_table + "." + field.DbField() + " as " + field.DbField()); } else { query.Get(field.DbField()); } } // Create the joins if (_linkTable != null) { query.Join(_linkTable, _hostField + " = " + _linkHostField); query.Join(_table, _childField + " = " + _linkChildField); } else { query.Join(_table, _childField + " = " + _hostField); } var result = query.Exec(); if (result.Count() != 0) { var readField = ""; var joinFieldName = _hostField.Split('.')[1]; if (NestedData.InData(_hostField, response.data[0])) { readField = _hostField; } else if (NestedData.InData(joinFieldName, response.data[0])) { readField = joinFieldName; } else if (!pkeyIsJoin) { throw new Exception( "Join was performed on the field '" + _hostField + "' which was not " + "included in the Editor field list. The join field must be " + "included as a regular field in the Editor instance." ); } // Map the data to the primary key for fast look up var join = new Dictionary <string, List <object> >(); Dictionary <string, object> row; while ((row = result.Fetch()) != null) { var inner = new Dictionary <string, object>(); foreach (var field in _fields.Where(field => field.Apply("get"))) { field.Write(inner, row); } var lookup = row["dteditor_pkey"].ToString(); if (!join.ContainsKey(lookup)) { join.Add(lookup, new List <object>()); } join[lookup].Add(inner); } // Loop over the data and do a join based on the data available foreach (var data in response.data) { var linkField = pkeyIsJoin ? (data["DT_RowId"].ToString()).Replace(editor.IdPrefix(), "") : NestedData.ReadProp(readField, data).ToString(); data.Add(_name, join.ContainsKey(linkField) ? join[linkField] : new List <object>() ); } } // Field options foreach (var field in _fields) { var opts = field.OptionsExec(editor.Db()); if (opts != null) { response.options.Add(_name + "[]." + field.Name(), opts); } } }