2017-10-15 22 views
1

请参阅calculateAge将LINQ查询中的出生日期转换为当前年数(它适用于其他键,例如:EyeColor,但适用于年龄转换失败),我想比较存储在数组中的值。我尝试将值存储在链接上方的DateTime temp变量中,正好在“case”AgeTo“:”下方,但我不能将值x.profile.BirthDate存储为仅在LINQ Query中允许的值。看来,在构建LINQ查询,不给错误,但是,它的失败精读从LINQ查询日期时间字段中计算年龄(使用C#进行比较)(Age From)

错误:

LINQ to Entities does not recognize the method 'Int32 calculateAge(System.DateTime)' method, and this method cannot be translated into a store expression.

任何帮助,如何处理?

代码和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; 
} 
+0

你知道如果你在午夜附近执行你的代码,如果可能会失败吗?最好在当前时间只询问一次,以确保搜索列表中的所有项目都使用相同的时间进行比较。也更容易编写一个体面的规范:“该函数计算函数被调用时集合中所有项目的年龄”。无论程序执行的速度如何,结果都是可预测的。另外考虑使用DateTime.Today,而不是DateTime.Now –

+0

好的一点,我会改变代码,回到我的成功。 – dotNETEngineer

回答

1

这里有一个简单的解决方案。比较年龄,比较日期本身。

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; 

这使得查询sargable,所以它可以使用索引的,假设你的好处已经创建了一个在BirthDate场。

+0

谢谢你的帮助马特JOHnson,这对我有效。 BirthDate字段是DateTime字段,它可以与转换后的maxDate或minDate变量进行比较。我很感谢帮助。 – dotNETEngineer

+0

有人可以回答以下(类似)的问题吗?这一次我需要与数值进行比较。 https://stackoverflow.com/questions/46855132/convert-to-int-from-string-from-linq-query-field-using-c-sharp-for-comparison-h – dotNETEngineer

2

你得到这个错误的原因是你的Where -clause被调用你的实体可查询,它不知道怎么翻译的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()来实现此目的。

+0

感谢罗布,看起来像我想念你的评论。我会试试看。 – dotNETEngineer

+1

Rob,我得到了它与马特的回应,感谢您的帮助。 DbFunctions类也相当实用。我会为未来的计算留下一张便条。 – dotNETEngineer

+0

嗨,有人可以查看SQL语法,并帮助我 - - https://stackoverflow.com/questions/47849473/select-statement-has-case-that-provies-select-value-sql-server – dotNETEngineer

0

您正在使用IQuearyable,因此在实现之前您不能将其与任意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; 
+0

有趣,谢谢,我会尝试... – dotNETEngineer

相关问题