注意:选中Update 1
部分
我正在使用jQuery DataTables,并实现了一种使用实体框架在asp.net MVC上使用服务器端借阅显示表记录的方法。
我面临的问题是我只能对记录中的string
数据类型进行全局搜索或单个列搜索。在int
和DateTime
类型的情况下,搜索不起作用。
以下实现仅在字符串类型的情况下有效。我不确定为什么该函数无法搜索int
和DateTime
类型,即使我在通过实体框架将SQL发送到数据库之前将它们转换为字符串也是如此。另外,我应该如何搜索bool
值?
注意,另一个挑战是我正在DataTable columnDefs render属性中进行自定义渲染,并作为响应更改了一些返回的JSON数据的显示值。例如,我正在使用int
转换switch
类型的列以在渲染表中显示文本格式。我找不到任何解决方案,以便用户搜索文本值,但是搜索使用关联的int
映射在表中返回新记录?
我已经包含了代码的所有不同部分。让我知道是否有任何遗漏,我将更新问题。
型号
using System;
using System.Collections.Generic;
using System.Data.Entity;
namespace SM.Models
{
public partial class LogEntryView
{
public Nullable<System.DateTime> log_time_stamp { get; set; }
public int log_id { get; set; }
public Nullable<int> request_type { get; set; }
public string user_id { get; set; }
public string workstation { get; set; }
public Nullable<System.DateTime> time_stamp { get; set; }
public string product_code_scheme { get; set; }
public string ProductCode { get; set; }
public string ProductName { get; set; }
public string Manufacturer { get; set; }
public string serial_number { get; set; }
public string batch { get; set; }
public string expiration_date { get; set; }
public Nullable<bool> manual_entry { get; set; }
public Nullable<int> command_status_code { get; set; }
public Nullable<int> pending { get; set; }
public Nullable<int> http_response_code { get; set; }
public Nullable<int> response_status_code { get; set; }
public Nullable<int> response_reason_code { get; set; }
public string response_operation_code { get; set; }
public string order_tracking_no { get; set; }
public string alert_id { get; set; }
public Nullable<bool> confirmed { get; set; }
public Nullable<System.DateTime> confirmed_date { get; set; }
public string return_code_desc { get; set; }
}
internal class LogEntryViewContext
{
public LogEntryViewContext()
{
Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
}
public DbSet<LogEntryView> LogEntryView { get; set; }
}
}
UTIL进行搜索/排序/分页(使用Link的引用)
using System;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Linq.Dynamic;
using System.Globalization;
using SM.Models;
namespace SM.Util
{
public static class ServerSideProcessor
{
public static IQueryable<T> ToGlobalSearchInAllColumn<T>(this IQueryable<T> table, DTParameters Param)
{
var GlobalSearchText = Param.Search != null && Param.Search.Value != null ? Param.Search.Value : string.Empty;
if (!string.IsNullOrEmpty(GlobalSearchText))
{
StringBuilder WhereQueryMaker = new StringBuilder();
Type RecordType = table.FirstOrDefault().GetType();
foreach (PropertyInfo prop in RecordType.GetProperties())
{
if (prop.PropertyType == typeof(System.String))
WhereQueryMaker.Append((WhereQueryMaker.Length == 0 ? "" : " OR ") + prop.Name + ".Contains(@0)");
else if (prop.PropertyType == typeof(System.Int32))
//if data type is integer then you need to parse to ToString() to use Contains() function
WhereQueryMaker.Append((WhereQueryMaker.Length == 0 ? "" : " OR ") + prop.Name + ".ToString().Contains(@0)");
else if (prop.PropertyType == typeof(System.DateTime?) && DateTime.TryParseExact(GlobalSearchText, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime CreatedOn))
//Date object comparison required to follow DateTime(2018,08,15) as format. so need to supply yyyy, MM, dd value on it.
WhereQueryMaker.Append((WhereQueryMaker.Length == 0 ? "" : " OR ") + prop.Name + "== DateTime(" + CreatedOn.Year + ", " + CreatedOn.Month + ", " + CreatedOn.Day + ")");
}
return table.Where(WhereQueryMaker.ToString(), GlobalSearchText);
}
return table;
}
public static IQueryable<T> ToIndividualColumnSearch<T>(this IQueryable<T> table, DTParameters Param)
{
if (Param.Columns != null && Param.Columns.Count() > 0 && table.FirstOrDefault() != null)
{
Type EntityType = table.FirstOrDefault().GetType();
var Properties = EntityType.GetProperties();
//listing necessary column where individual columns search has applied. Filtered with search text as well it data types
Param.Columns.Where(w => w.Search != null &&
!string.IsNullOrEmpty(w.Search.Value)).ToList().ForEach(x =>
{
//x.Data is column name as string format coming from Param object.
//x.Search.Value specific search text applied on column
//Added extra check on column name coming from Param and its data type on search text.
if (int.TryParse(x.Search.Value, out int Id) && Properties.Count(p => p.Name == x.Data && p.PropertyType == typeof(System.Int32)) > 0)
table = table.Where(x.Data + ".ToString().Contains(@0)", x.Search.Value);
else if (DateTime.TryParseExact(x.Search.Value, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime CreatedOn) && Properties.Count(p => p.Name == x.Data && p.PropertyType == typeof(System.DateTime?)) > 0)
table = table.Where(x.Data + "==DateTime(" + CreatedOn.Year + ", " + CreatedOn.Month + ", " + CreatedOn.Day + ")");
else if (Properties.Count(p => p.Name == x.Data && p.PropertyType == typeof(System.String)) > 0)
table = table.Where(x.Data + ".Contains(@0)", x.Search.Value);
});
}
return table;
}
public static IQueryable<T> ToSorting<T>(this IQueryable<T> table, DTParameters Param)
{
//Param.SortOrder return sorting column name
//Param.Order[0].Dir return direction as asc/desc
return table.OrderBy(Param.SortOrder + " " + Param.Order[0].Dir).AsQueryable();
}
public static IQueryable<T> ToPagination<T>(this IQueryable<T> table, DTParameters Param)
{
//Param.Start return start index
//Param.Length page length
if (Param.Length > 0)
return table.Skip(Param.Start).Take(Param.Length);
else return table.Skip(Param.Start);
}
}
}
DAL
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Linq.Dynamic;
using SM.Models;
using SM.Util;
namespace SM.DAL
{
public class EventLogsDAL
{
public List<LogEntryView> Read(DTParameters Param, out int Count)
{
using (var Context = new LogEntryViewContext())
{
Count = Context.LogEntryView.Count();
// Fetch all records
var LogEntryViewData = from tempLogEntryViewData in Context.LogEntryView select tempLogEntryViewData;
// default orderBy
LogEntryViewData = LogEntryViewData.OrderBy(t => t.log_time_stamp);
// Global Text Search
var GlobalSearchFilteredData = LogEntryViewData.ToGlobalSearchInAllColumn(Param);
// Search Text in Specific or Individual
var IndividualColSearchFilteredData = GlobalSearchFilteredData.ToIndividualColumnSearch(Param);
// Sorting order
var SortedFilteredData = IndividualColSearchFilteredData.ToSorting(Param);
// Apply Pagination (Taking N number by page size)
var SortedData = SortedFilteredData.ToPagination(Param).ToList();
return SortedData;
}
}
}
}
控制器
using Newtonsoft.Json;
using SM.DAL;
using SM.Models;
using SM.Util;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Web.Mvc;
namespace SMApp.Controllers
{
public class HomeController : Controller
{
public ActionResult ShowEventLogs()
{
return View();
}
[HttpPost]
public ActionResult ShowEventLogs(DTParameters param)
{
using (ISMDatabase db = new SMDatabase(this))
{
EventLogsDAL ed = new EventLogsDAL();
var Result = ed.Read(param, out int Count);
DTResult<LogEntryView> result = new DTResult<LogEntryView>
{
draw = param.Draw,
data = Result,
recordsFiltered = Count,
recordsTotal = Count
};
JsonSerializerSettings jsSettings = new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
string json = JsonConvert.SerializeObject(result, jsSettings);
return Content(json, "application/json");
}
}
}
}
查看
<table id="event-log-table">
<thead>
<tr>
<th>Time</th>
<th>User</th>
<th>Command</th>
<th>Scheme</th>
<th>Product Code</th>
<th>Serial Number</th>
<th>Batch</th>
<th>Exp Date</th>
<th>Http Code</th>
<th>Log Id</th>
<th>Is Confirmed?</th>
<th>Confirmation Date</th>
<th>Verify Pack</th>
<th>Status</th>
<th>Product Name</th>
<th>Manufacturer</th>
<th>Alert ID</th>
<th>Workstation</th>
<th>Order Tracking No.</th>
<th>Response text</th>
</tr>
</thead>
<tfoot>
<tr>
<th>Time</th>
<th>User</th>
<th>Command</th>
<th>Scheme</th>
<th>Product Code</th>
<th>Serial Number</th>
<th>Batch</th>
<th>Exp Date</th>
<th>Http Code</th>
<th>Log Id</th>
<th>Is Confirmed?</th>
<th>Confirmation Date</th>
<th>Verify Pack</th>
<th>Status</th>
<th>Product Name</th>
<th>Manufacturer</th>
<th>Alert ID</th>
<th>Workstation</th>
<th>Order Tracking No.</th>
<th>Response text</th>
</tr>
</tfoot>
<tbody></tbody>
</table>
JavaScript(用于DataTables初始化)
$('#event-log-table').DataTable({
"processing": true, // for show progress bar
"serverSide": true, // for process server side
"autoWidth": false,
"ajax": {
"url": "ShowEventLogs",
"type": "POST",
"datatype": "json"
},
columnDefs: [{
"targets": 0,
"data": "log_time_stamp",
"defaultContent": "Not Initialized"
},
{
"targets": 1,
"data": "user_id",
"defaultContent": "Unknown"
},
{
"targets": 2,
"data": "command_status_code",
"defaultContent": "Unknown",
"render": function(data, type, row) {
switch (data) {
case 0:
return 'Verify';
case 1:
return 'Mark as Active';
case 2:
return 'Mark as Dispense';
case 3:
return 'Mark as Stolen';
case 4:
return 'Mark as Destroyed';
case 5:
return 'Mark as Sample"';
case 6:
return 'Mark as Free Sample';
case 7:
return 'Mark as Locked';
case 8:
return 'Mark as Exported';
case 9:
return 'Mark as Checkout';
case 10:
return 'Mark as Expired';
case 11:
return 'Mark as Recalled';
case 12:
return 'Mark as Withdrawn';
}
}
},
{
"className": "product_code_scheme",
"targets": 3,
"data": "product_code_scheme",
"defaultContent": "Unknown"
},
{
"targets": 4,
"className": "ProductCode",
"data": "ProductCode",
"defaultContent": "Not Found"
},
{
"targets": 5,
"className": "serial_number",
"data": "serial_number",
"defaultContent": "Not Found"
},
{
"targets": 6,
"className": "batch",
"data": "batch",
"defaultContent": "Not Found"
},
{
"targets": 7,
"className": "expiration_date",
"data": "expiration_date",
"defaultContent": "Not Found"
},
{
"targets": 8,
"data": "http_response_code",
"defaultContent": "Unknown"
},
{
"className": "log_id",
"targets": 9,
"data": "log_id",
"defaultContent": "Not Found"
},
{
"targets": 10,
"data": "confirmed",
"defaultContent": "Unknown",
"render": function(data, type, row) {
switch (data) {
case true:
return 'Yes';
case false:
return 'No';
}
}
},
{
"targets": 11,
"data": "confirmed_date",
"defaultContent": "Not yet initialized"
},
{
"targets": 12,
"defaultContent": "N.A",
"render": function(data, type, full, meta) {
if (full.http_response_code === 202 && full.confirmed === false) {
return '<a class="verify-pack tx-info" style="cursor: pointer">Verify Pack</a>';
} else if (full.http_response_code === 202 && full.confirmed === true) {
return '<a class="tx-info">Already Verified</a>';
}
}
},
{
"targets": 13,
"data": "pending",
"defaultContent": "Unknown",
"render": function(data, type, row) {
switch (data) {
case 0:
return 'Unprocessed';
case 1:
return 'Pending';
case 2:
return 'Completed';
}
}
},
{
"targets": 14,
"data": "ProductName",
"defaultContent": "Not Found"
},
{
"targets": 15,
"data": "Manufacturer",
"defaultContent": "Not Found"
},
{
"targets": 16,
"data": "alert_id",
"defaultContent": "Not Found"
},
{
"targets": 17,
"data": "workstation",
"defaultContent": "Not Found"
},
{
"targets": 18,
"data": "order_tracking_no",
"defaultContent": "Not Found"
},
{
"targets": 19,
"data": "return_code_desc",
"defaultContent": "Not Found"
}
],
initComplete: function() {
// Setup - add a text input to each footer cell
$('#event-log-table tfoot th').each(function() {
var title = $(this).text();
$(this).html('<input type="text" class="form-control fc-focus-info wd-90p" />');
});
// Apply the search
eventLogTable.columns().every(function() {
var that = this;
$('input', this.footer()).on('keyup', function() {
if (that.search() !== this.value) {
that.search(this.value).draw();
}
});
});
}
});
更新1
在查询数据库时,通过使用DTO包装器,我设法使搜索工具功能适用于non-nullable
int
和DateTime
数据类型。
添加了以下模型包装器(基本上是模型LogEntryView的副本)
public class LogEntryViewDTO
{
public Nullable<System.DateTime> log_time_stamp { get; set; }
public int log_id { get; set; }
public Nullable<int> request_type { get; set; }
public string user_id { get; set; }
public string workstation { get; set; }
public Nullable<System.DateTime> time_stamp { get; set; }
public string product_code_scheme { get; set; }
public string ProductCode { get; set; }
public string ProductName { get; set; }
public string Manufacturer { get; set; }
public string serial_number { get; set; }
public string batch { get; set; }
public string expiration_date { get; set; }
public Nullable<bool> manual_entry { get; set; }
public Nullable<int> command_status_code { get; set; }
public Nullable<int> pending { get; set; }
public Nullable<int> http_response_code { get; set; }
public Nullable<int> response_status_code { get; set; }
public Nullable<int> response_reason_code { get; set; }
public string response_operation_code { get; set; }
public string order_tracking_no { get; set; }
public string alert_id { get; set; }
public Nullable<bool> confirmed { get; set; }
public Nullable<System.DateTime> confirmed_date { get; set; }
public string return_code_desc { get; set; }
}
并将DAL红色功能修改为
public List<LogEntryViewDTO> Read(DTParameters Param, out int Count, string currentUserName, bool isInGroup4)
{
using (var Context = new LogEntryViewContext(country))
{
Count = Context.LogEntryView.Count();
// Fetch all records
var LogEntryViewData = Context.LogEntryView.Select(t => new LogEntryViewDTO()
{
log_time_stamp = t.log_time_stamp,
log_id = t.log_id,
request_type = t.request_type,
user_id = t.user_id,
workstation = t.workstation,
time_stamp = t.time_stamp,
product_code_scheme = t.product_code_scheme,
ProductCode = t.ProductCode,
ProductName = t.ProductName,
Manufacturer = t.Manufacturer,
serial_number = t.serial_number,
batch = t.batch,
expiration_date = t.expiration_date,
manual_entry = t.manual_entry,
command_status_code = t.command_status_code,
pending = t.pending,
http_response_code = t.http_response_code,
response_status_code = t.response_status_code,
response_reason_code = t.response_reason_code,
response_operation_code = t.response_operation_code,
order_tracking_no = t.order_tracking_no,
alert_id = t.alert_id,
confirmed = t.confirmed,
confirmed_date = t.confirmed_date,
return_code_desc = t.return_code_desc
}).AsQueryable();
// Check if user is not in Group 4
if (!isInGroup4)
{
LogEntryViewData = LogEntryViewData.Where(t => t.user_id == currentUserName);
}
// default orderBy
LogEntryViewData = LogEntryViewData.OrderBy(t => t.log_time_stamp);
// Global Text Search
var GlobalSearchFilteredData = LogEntryViewData.ToGlobalSearchInAllColumn(Param);
// Search Text in Specific or Individual
var IndividualColSearchFilteredData = GlobalSearchFilteredData.ToIndividualColumnSearch(Param);
// Sorting order
var SortedFilteredData = IndividualColSearchFilteredData.ToSorting(Param);
// Apply Pagination (Taking N number by page size)
var SortedData = SortedFilteredData.ToPagination(Param).ToList();
return SortedData;
}
}
因此,它解决了我在int / DateTime类型中进行搜索的问题,但仅当未将它们定义为nullable
例如,它搜索int
列
public int log_id { get; set; }
但不包括以下
public Nullable<System.DateTime> log_time_stamp { get; set; }
public Nullable<int> request_type { get; set; }
public Nullable<System.DateTime> time_stamp { get; set; }
public Nullable<bool> manual_entry { get; set; }
public Nullable<int> command_status_code { get; set; }
public Nullable<int> pending { get; set; }
public Nullable<int> http_response_code { get; set; }
public Nullable<int> response_status_code { get; set; }
public Nullable<int> response_reason_code { get; set; }
public Nullable<bool> confirmed { get; set; }
public Nullable<System.DateTime> confirmed_date { get; set; }