c# - 首先在 Entity Framework 代码中使用搜索字符串搜索 DateTime

标签 c# .net sql-server entity-framework datetime

我有一个 MVC 项目,它为每个模型项输出一个可为空的 DateTime (DateTime?) 作为字符串给用户,如下所示(我的用户界面有分页,所以我只为少量记录——换句话说,这部分没问题):

foreach (DocumentEvent item in Model.items)
    @(item?.TimeUtc?.ToString() ?? "N/A")

我想添加一个搜索功能。我试过如下搜索,但这不是高效的,因为 AsEnumerable 实现了我的列表,而我现在在 C# 世界中,枚举每条记录:

using (var context = new ClientEventsContext())
    var items = context.Events.AsEnumerable().Where(x => {
        (x?.TimeUtc?.ToString() ?? "N/A").Contains(model.search)
    });

相反,我想利用我的 SQL Server 数据库。如何在不使用 AsEnumerable 的情况下为上述代码构建 SQL Server 友好的查询,从而产生与当前逻辑相同的结果?

最佳答案

此处介绍了如何构建和使用 LINQ to Entities 兼容的从日期到 M/d/yyyy h:mm:ss tt 格式字符串的转换。我将使用自定义“标记”方法并使用 ExpressionVisitor 绑定(bind)实现,而不是将这个怪物嵌入查询中。通过这种方式,您可以根据需要试验和更改格式(甚至添加一些控制参数),而不会影响查询的可读性。

一、实现:

public static class EFExtensions
{
    public static string ToCustomDateFormat(this DateTime value)
    {
        // Should never happen
        throw new InvalidOperationException();
    }

    public static IQueryable<T> ApplyCustomDateFormat<T>(this IQueryable<T> source)
    {
        var expression = new CustomDateFormatBinder().Visit(source.Expression);
        if (source.Expression == expression) return source;
        return source.Provider.CreateQuery<T>(expression);
    }

    class CustomDateFormatBinder : ExpressionVisitor
    {
        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            if (node.Method.DeclaringType == typeof(EFExtensions) && node.Method.Name == "ToCustomDateFormat")
            {
                var date = Visit(node.Arguments[0]);
                var year = DatePart(date, v => DbFunctions.Right("0000" + v.Year, 4));
                var month = DatePart(date, v => v.Month.ToString());
                var day = DatePart(date, v => v.Day.ToString());
                var hour = DatePart(date, v => (1 + (v.Hour + 11) % 12).ToString());
                var minute = DatePart(date, v => DbFunctions.Right("0" + v.Minute, 2));
                var second = DatePart(date, v => DbFunctions.Right("0" + v.Second, 2));
                var amPM = DatePart(date, v => v.Hour < 12 ? "AM" : "PM");
                var dateSeparator = Expression.Constant("/");
                var timeSeparator = Expression.Constant(":");
                var space = Expression.Constant(" ");
                var result = Expression.Call(
                    typeof(string).GetMethod("Concat", new Type[] { typeof(string[]) }),
                    Expression.NewArrayInit(typeof(string),
                        month, dateSeparator, day, dateSeparator, year, space,
                        hour, timeSeparator, minute, timeSeparator, second, space, amPM));
                return result;    
            }
            return base.VisitMethodCall(node);
        }

        Expression DatePart(Expression date, Expression<Func<DateTime, string>> part)
        {
            var parameter = part.Parameters[0];
            parameterMap.Add(parameter, date);
            var body = Visit(part.Body);
            parameterMap.Remove(parameter);
            return body;
        }

        Dictionary<ParameterExpression, Expression> parameterMap = new Dictionary<ParameterExpression, Expression>();

        protected override Expression VisitParameter(ParameterExpression node)
        {
            Expression replacement;
            return parameterMap.TryGetValue(node, out replacement) ? replacement : node;
        }
    }
}

然后是用法:

var items = context.Events
    .Where(x => x.TimeUtc != null && 
        x.TimeUtc.Value.ToCustomDateFormat().Contains(model.search))
    .ApplyCustomDateFormat();

关于c# - 首先在 Entity Framework 代码中使用搜索字符串搜索 DateTime,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40312120/

相关文章:

c# - Sendgrid:在一个请求中向不同的收件人发送不同的邮件

c# - 通过序列化 DataContract 将对象字段分离到两个文件中

c# - 如何从共享类中访问 ViewState?

mysql - NodeJS + MySQL,在插入时无法从应用程序访问数据库,但可以从终端访问

sql - 在 SQL Server 中定义动态 PIVOT sql 查询

c# - SpinWait.SpinUntil 的替代方案

.net - 将 F# 用于 BLL 实现是否有意义?

c# - 是否可以(使用 Moq)对带有 Lambda 参数的方法调用进行 stub ?

.net - 将 32 位库链接到 64 位 .NET 应用程序和内存消耗

sql-server - 如何在 SQL Server 2005 中锁定表?我应该这样做吗?