使用DataTable和Entity Framework / Linq在ASP.NET MVC中搜索可为空的数据类型

时间:2019-04-14 22:21:36

标签: c# jquery asp.net-mvc linq datatables

注意:选中Update 1部分

我正在使用jQuery DataTables,并实现了一种使用实体框架在asp.net MVC上使用服务器端借阅显示表记录的方法。

我面临的问题是我只能对记录中的string数据类型进行全局搜索或单个列搜索。在intDateTime类型的情况下,搜索不起作用。

以下实现仅在字符串类型的情况下有效。我不确定为什么该函数无法搜索intDateTime类型,即使我在通过实体框架将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();
                }
            });
        });
    }
});

渲染表 enter image description here

更新1

在查询数据库时,通过使用DTO包装器,我设法使搜索工具功能适用于non-nullable intDateTime数据类型。

添加了以下模型包装器(基本上是模型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; }

0 个答案:

没有答案