使用EntityFrameWork时,经常会用到lambda表达式来做查询等操作,由于EF要根据表达式生成最终操作数据库的SQL,所以在表达式中加入其它方法如”parse”,”convert”可能会导致不被LinqToEntity识别,异常如下:

System.NotSupportedException: LINQ to Entities does not recognize the method int.Parse(System.String)

但在实际项目中往往会遇到实体字段类型与参数类型需要转换并比较的问题:

问题1: 字段int型与参数string型的比较

例:

实体People的Age属性为Int

参数alduts为String型,值为”18”

需要找出People表中所有Age大于18的实体集合

解答:

这类问题相对比较好解决,只需要在lambda表达式外部先对参数做类型转换

错误方法:

1
entities.People.Where(l=>l.Age > int.Parse(alduts));

正确方法:

1
2
int aldutsAge = int.Parse(alduts);
entities.People.Where(l=>l.Age > aldutsAge);

问题2: 字段string型与参数int型的比较

例:

实体People的Age属性为String

参数alduts为Int型,值为”18”

需要找出People表中所有Age大于18的实体集合

解答:

这类问题相对复杂,可考虑三种方式:

方法一:直接使用SQL

在EF4.0以后可通过EF直接用SQL操作数据库

entities.Database.ExecuteSqlCommand
entities.Database.SqlQuery

这里可以使用SQL的”CAST”方法将Age转换为int类型

select * from People where CAST(Age as int) > @alduts

需要注意的是CAST方法在多数数据库下都可用,而convert方法只在SQL SERVER中可用,所以写SQL时一定要考虑到数据库的通用性

方法二:考虑修改Age字段类型

在条件允许的前提下可修改Age字段类型为Int型,使用这种方法能彻底避免转换问题与数据库兼容问题

方法三:在CSDL自定义函数实现字段类型转换

由于使用”方法一”会导致实体操作方式不统一, 同时还会降低代码复用性,所以这里可以定义一个通用的转换方法。

步骤:

1.右键”实体模型edmx”,选择打开方式为“XML文本编辑器”

2.找到CSDL分支

3.在”Schema”分支下添加下面的代码:

<Function Name="ConvertToInt32" ReturnType="Edm.Int32">
  <Parameter Name="v" Type="String" />
  <DefiningExpression>
    CAST(v as Edm.Int32)
  </DefiningExpression>
</Function>
<Function Name="ConvertToDouble" ReturnType="Edm.Double">
  <Parameter Name="v" Type="String" />
  <DefiningExpression>
    CAST(v as Edm.Double)
  </DefiningExpression>
</Function>

其中ReturnType为返回值类型,支持的类型有:

这里可以看到DefiningExpression其实就是一个SQL。修改完成后保存退出。

4.使用转换方法,需加入EdmFunction的Attribute(EF6后更名为DbFunction)

1
2
3
4
5
6
7
8
9
10
11
[EdmFunction("testModel", "ConvertToInt32")]
public static int ConvertToInt32(string value)
{
throw new InvalidOperationException("Only valid when used as part of a LINQ query.");
}
[EdmFunction("testModel", "ConvertToDouble")]
public static double ConvertToDouble(string value)
{
throw new InvalidOperationException("Only valid when used as part of a LINQ query.");
}

其中参数1为实体的NamespaceName,参数2为FunctionName。

5.在LinqToEntity中使用转换方法

1
entities.People.Where(l=>ConvertToInt32(l.Age) > 18);

问题3: DateTime的比较

在LinqToEntity中,诸如Datetime的直接比较也是不允许的,但EF中提供了System.Data.Objects.EntityFunctions类(EF6.0后改为System.Data.Entity.DbFunctions),使用该类下的方法可以可以完成时间比较的操作,具体可参考MSDN

需要注意的是还有一个功能类似的类SQLFunctions,这两个类都是将LinqToEntity翻译成SQL,但SQLFunctions具体针对SQLServer,而EntityFunctions通用性更广。