动态LINQ(到实体)其中DateTime列可为空

ubof19bj  于 2022-12-15  发布在  其他
关注(0)|答案(4)|浏览(165)

我一直在思考这个问题。有一些类似的案例,但解决方案不适用于我的案例。
我有一个方法,返回字符串格式的过滤器查询。该方法有不同的数据类型的逻辑,设置正确的值,列名等。

string filterQuery = GetFilterQuery(params);
rows = rows.Where(filterQuery);

我的问题是数据库中有Nullable DateTime,而代码端有String表示。
我已经尝试了以下查询(String表示目前可能是错误的):

"BirthDate.ToString() = \"16.2.2012 22:00:00\""

结果:* 类型“DateTime?”上的方法不可访问 *

"BirthDate.Value.ToString() = \"16.2.2012 22:00:00\""

结果LINQ to Entities无法识别方法“System.String ToString()",因此无法将此方法转换为存储表达式。

"BirthDate == null ? 1=1 : (DateTime)BirthDate.ToString() = \"16.2.2012 22:00:00\""

结果:* 应为.“"或”(“”*

有解决这个问题的办法吗?

更新(添加了更多关于查询生成的源代码)

var filterQueries = query.GridFilteringOptions.filters
    // remove filters that doesn't have all the required information
    .Where(o => o.name != string.Empty && o.value != string.Empty && !string.IsNullOrEmpty(o.type))
    // remove filters that are filtering other tables than current
    .Where(o => o.table == tableName) 
    .Select(filter => filter.ResolveQuery()).ToList();

if (filterQuery.Any())
{
    var filterQuery = string.Join(" And ", filterQueries);
    rows = rows.Where(filterQuery);
}

这里有一个类Filter和与此上下文相关的方法

public string ResolveQuery()
{
    if (type == "Int64")
    {
        return ResolveInteger();
    }
    else if(type == "String")
    {
        return ResolveString();
    }
    else if(type == "DateTime")
    {
        return ResolveDateTime();
    }
    else
    {
        return string.Empty;
    }
}

private string ResolveDateTime()
{
    DateTime result = new DateTime();
    if (DateTime.TryParse(this.value, out result))
    {
        return string.Format("{0}.ToString() = \"{1}\"", this.name, result.ToUniversalTime());
    }
    return string.Empty;
}

private string ResolveString()
{
    switch (@operator)
    {
        default:
            return string.Format(@"{0}.StartsWith(""{1}"")", this.name, this.value);
    }            
}

private string ResolveInteger()
{
    string tmp = this.name;
    switch (@operator)
    {
        case -1:
            return string.Empty;
        case 0:
            tmp += "<";
            break;
        case 1:
            tmp += "=";
            break;
        case 2:
            tmp += ">";
            break;
        default:
            return string.Empty;
    }
    tmp += value;
    return tmp;
}
m0rkklqb

m0rkklqb1#

LINQ to Entities无法识别ToString()方法。在将结果字符串插入查询之前,您必须对其进行求值。
要在你的问题中创建示例,你可以这样处理它:

// "BirthDate.ToString() = \"16.2.2012 22:00:00\""
string birthdate = BirthDate.ToString();
string query = String.Format("{0}  = \"16.2.2012 22:00:00\"", birthdate);

// "BirthDate.Value.ToString() = \"16.2.2012 22:00:00\""
string birthdate = BirthDate.Value.ToString();
string query = String.Format("{0}  = \"16.2.2012 22:00:00\"", birthdate);

"BirthDate == null ? 1=1 : (DateTime)BirthDate.ToString() = \"16.2.2012 22:00:00\""可能不起作用,因为LINQ to EF无法识别三元运算符(? :

**编辑:**我从你的评论中了解到BirthDate是你的表中的一列,而不是一个变量。在这种情况下,你可以检索所有的条目,将它们转换成一个列表,然后使用LINQ对对象应用过滤器,如下所示(尽管你必须相应地修改你的filterQuery):

string filterQuery = GetFilterQuery(params);
var filteredRows = rows.ToList().Where(filterQuery);

**未测试:**可能会使用数据库的CONVERT函数:

string query = "CONVERT(varchar(20), BirthDate) = \"16.2.2012 22:00:00\"";
eimct9ow

eimct9ow2#

我的问题是,我在数据库中有可为空的DateTime,而在代码端有String表示。
为什么?
更改代码端,分析字符串表示形式,并在LINQ查询中为它指定适当的对象。
“出生日期.ToString()=“2012年2月16日22:00:00””
坏-如果你必须做字符串操作,AWLWAYS使用InvariantCulture。这段代码很脆弱,在任何其他国家都会崩溃。

cbjzeqam

cbjzeqam3#

我目前用try/catch块来解决这个问题,这增加了一些开销和丑陋,我宁愿找到一个替代方案,但它确实工作得很稳定:

try
{
    // for strings and other non-nullables
    records = records.Where(rule.field + ".ToString().Contains(@0)", rule.data);
}
catch (System.Linq.Dynamic.ParseException)
{
    // null types
    records = records.Where(rule.field + ".Value.ToString().Contains(@0)", rule.data);
}

注:从输入变量(rule.fieldrule.data)接受这些字段是危险的,可能会导致(困难的)盲目SQL注入。可以根据值白名单检查第一个值(rule.field),以防止出现这种情况。

pod7payv

pod7payv4#

我知道我的回答有点晚,但对于每一个仍然在同一个案件中挣扎的人,你可以尝试这个解决方案

DateTime.Parse(BirthDate.ToString()).Date = DateTime.Parse(\"16.2.2012 22:00:00\"")

这样,无论出生日期是DateTime还是DateTime?,它都将工作。最好检查出生日期之前是否不为空

BirthDate != null && DateTime.Parse(BirthDate.ToString()).Date = DateTime.Parse(\"16.2.2012 22:00:00\""

方法.ToString()适用于日期时间和可为空的日期时间

相关问题