繁体   English   中英

使用C#进行比较的LINQ查询DateTime字段中的computeAge(或年份)(Age From)

[英]calculateAge (or year) from LINQ Query DateTime field using C# for comparision (Age From)

请参阅calculateAge在LINQ查询中将出生日期转换为以年为单位的当前年龄(它适用于其他键,例如:EyeColor,但年龄转换失败),我想与存储在数组中的值进行比较。 我尝试将值存储在链接上方,“ case“ AgeTo”:“正下方的DateTime临时变量中,但我无法采用x.profile.BirthDate值,因为仅在LINQ Query中允许使用它。 看起来LINQ查询在构建期间没有给出错误,但是,它无法

错误:

LINQ to Entities无法识别方法'Int32calculateAge(System.DateTime)'方法,并且该方法无法转换为商店表达式。

任何帮助如何处理?

代码和calculateAge方法:

if (searchList.Count > 0)
{
    foreach (KeyValuePair<String, String> kvp in searchList)
    {
        switch (kvp.Key)
        {
            case "AgeFrom":
                photosquery = photosquery.Where(x => calculateAge(Convert.ToDateTime(x.profile.BirthDate)) >= Convert.ToInt32(kvp.Value));
                break;
            case "AgeTo":
                photosquery = photosquery.Where(x => calculateAge(Convert.ToDateTime(x.profile.BirthDate)) <= Convert.ToInt32(kvp.Value));
                break;
            case "EyeColor":
                photosquery = photosquery.Where(x => x.physical.EyesColor.Contains(kvp.Value));
                break;
        }
    }
}

//My code for calculateAge:

public static int calculateAge(DateTime birthDay)
{
    int years = DateTime.Now.Year - birthDay.Year;

    if ((birthDay.Month > DateTime.Now.Month) || (birthDay.Month == DateTime.Now.Month && birthDay.Day > DateTime.Now.Day))
        years--;

    return years;
}

出现此错误的原因是, Where可查询的Entity上调用了Where-子句,并且它不知道如何将C#代码转换为数据库语言的等效代码。

如果您能够将该函数的内部重写为不具有基于.NET的变量存储或仅引用数据库中可用的CLR函数的东西,则可以内联使用它,就好像您没有该函数一样呼叫:

var now = DateTime.Now;
...    
case "AgeFrom":
    photosquery = photosquery.Where(x => DbFunctions.DiffYears(x.profile.BirthDate,now) >= Convert.ToInt32(kvp.Value));
    break;

如果要使用已有的代码,则需要在过滤之前检索所有数据,通常不建议这样做。 您仍然可以通过在.Where(..)子句之前调用.ToList()来实现此目的。

有一个更简单的解决方案。 与其比较年龄,不如比较日期本身。

case "AgeFrom":
    var fromAge = Convert.ToInt32(kvp.Value);
    var maxDate = DateTime.Today.AddYears(-fromAge);
    photosquery = photosquery.Where(x => x.profile.BirthDate <= maxDate);
    break;
case "AgeTo":
    var toAge = Convert.ToInt32(kvp.Value);
    var minDate = DateTime.Today.AddYears(-toAge-1).AddDays(1);
    photosquery = photosquery.Where(x => x.profile.BirthDate >= minDate);
    break;

这具有使查询成为可扩展查询的额外好处,因此假设您已在BirthDate字段上创建了一个索引,则它可以利用索引。

您正在使用IQueryable ,因此无法在实现之前将其与任意C#代码混合使用。

现在,您有两个选择:

  1. 使用ToListToArray将所有数据加载到应用程序内存中,然后应用过滤方法
  2. 重写查询以使用某些sql函数(在这种情况下为DATEPART

对于第二种方法,您可以编写此查询(在switch之前):

var newQuery = photosquery.Select(x => new
{
    AllQuery = x,
    yearsDiff = (x.profile.BirthDate.Month > now.Month) ||
                (x.profile.BirthDate.Month == now.Month 
                   && x.profile.BirthDate.Day > now.Day)
        ? now.Year - x.profile.BirthDate.Year - 1
        : now.Year - x.profile.BirthDate.Year
});

然后,当您输入switch您可以写:

case "AgeFrom":
  photosquery = newQuery
      .Where(x => x.yearsDiff >= Convert.ToInt32(kvp.Value))
      .Select(x => x.AllQuery );
  break;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM