实体框架不支持x.ToString()!

时间:2011-06-02 10:02:54

标签: c# .net entity-framework linq-to-entities

实体框架无法识别将路径对象转换为特定字符串的ToString方法:

public IEnumerable<Route> GetRoutes(string prefix, string searchPattern, string code)
{
    return Routes.
        Where(x => code == null || x.Code == code).
        Where(x => searchPattern == null || x.ToString().Contains(searchPattern)).
        Where(x => prefix == null || x.ToString().StartsWith(prefix));
}

这是我的路线实体:

 public class Route : IDataEntity, ISoftDeletable
    {
        public virtual long Id { get; set; }
        public virtual string Code { get; set; }
        public virtual bool IsDeleted { get; set; }
        public virtual Guid CompanyId { get; set; }
        public virtual IList<LocationInRoute> Locations { get; set; }

        public override string ToString()
        {
            StringBuilder str = new StringBuilder();
            foreach (LocationInRoute loc in Locations)
            {
                if (str.Length > 0)
                {
                    str.Append(" > ");
                }
                str.Append(loc.ToString());
            }
            return str.ToString();
        }
    }

所有x.ToString()抛出了linq对实体不支持的异常。 任何解决方法?

6 个答案:

答案 0 :(得分:2)

  

实体框架无法识别将路径对象转换为特定字符串的ToString方法。

没错。实体框架无法将您在c#中编写的方法转换为sql。

实体框架将表达式转换为sql。有时这些表达式表示对方法的调用(例如Queryable.Where),实体框架知道那些特定的.net框架方法以及如何将它们转换为sql。

您希望数据库如何新建一个StringBuilder?


PS:查询中的这个或者标准是一种可怕的方式。您不应该构造一个查询来统治它们。相反,有条件地构造查询:

IQueryable<Route> query = Routes

if (code != null)
{
  query = query.Where(x => x.Code == code)
}
if (searchPattern != null)
{
  query = query.Where(x => x.Locations.Any(loc => loc.Name.Contains(searchPattern)))
}
if (prefix != null)
{
  query = query.Where(x => x.Locations.First().Name.StartsWith(prefix));
}

答案 1 :(得分:2)

您不能在客户端(ToString)执行此操作。

您必须创建将执行评估的SQL函数 - 它可以只对您的位置进行字符串连接(我相信它是相关实体),或者您可以在自定义函数中执行整个测试。然后,您可以将该函数导入实体模型(EDMX)并创建EdmFunctionAttribute来调用它 - MSDN

答案 2 :(得分:1)

您需要指定需要与RoutesearchPattern进行比较的prefix课程属性。您不能在您的方案中隐式执行.ToString()

答案 3 :(得分:1)

我认为你必须有一个名为IDName的属性,你要与searchPattern进行比较,然后使用:

 .Where(x => searchPattern == null || x.Name.Contains(searchPattern));

因为我认为x展示了一个实体,所以,你想如何将entiy的名称本身与搜索模式进行比较呢?

修改

在看到问题中的更改后,它仍然无法在此查询中使用ToString()方法,因为它无法转换为SQL语句。

现在,您有两种选择:

第一个:(我不确定是否适用取决于可疑的数据大小),尝试使用ToList()扩展名从数据库加载所有记录,然后再调用Where扩展名。 这应该可以正常工作,但它可能会导致巨大的表格出现问题。

第二个:你必须创建一个存储过程并将逻辑移动到数据库。

答案 4 :(得分:1)

较新版本的Entity Framework(从6.1版开始)支持

ToString()

参见EF 6.1的Release Notes

  

EF6.1中的内容

     

EF6.1增加了以下新功能:
  [...]

     
      
  • 在LINQ查询中支持.ToString,String.Concat和enum HasFlags。
  •   

(嗯,问题已经有几年了,但也许这些信息可能有助于其他人...... 另见相关问题How to use ToString SelectListItem with Entity Framework?

答案 5 :(得分:0)

This postthis post可能会提供一些帮助。请注意,第二个链接中建议的方法不适用于LINQ to Entities,因为它使用ToString。要使其工作,请使用以下命令替换CreateLike方法:

private static Expression<Func<T, bool>> CreateLike<T>( PropertyInfo prop, string value )
{
    var parameter = Expression.Parameter( typeof( T ) );
    Expression instanceExpression = Expression.MakeMemberAccess( parameter, prop );            
    if( prop.PropertyType != typeof( System.String ) )
    {
        var cast = Expression.Convert( instanceExpression, typeof( double? ) );
        MethodInfo toString = typeof( SqlFunctions ).GetMethods().First( m => m.Name == "StringConvert" && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof( double? ) );
        instanceExpression = Expression.Call( toString, cast );                
    }
    var like = Expression.Call( instanceExpression, "Contains", null, Expression.Constant( value, typeof( string ) ) );
    return Expression.Lambda<Func<T, bool>>( like, parameter );
}