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

问题描述 投票:0回答:7

实体框架无法识别我的将路由对象转换为指定字符串的 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 toEntity 中不支持的异常。 有什么解决办法吗?

c# .net entity-framework linq-to-entities
7个回答
2
投票

您无法在客户端执行此操作 (

ToString
)。

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

EdmFunctionAttribute
来调用它 - MSDN


2
投票

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

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

实体框架将表达式转换为sql。有时,这些表达式表示对方法的调用(例如

Queryable.Where
),实体框架了解这些特定的 .net 框架方法以及如何将它们转换为 sql。

你期望数据库如何新建一个StringBuilder?


PS:查询中条件的这种 or'ing 是一种糟糕的方法。您不应该构建一个查询来统治所有这些查询。相反,有条件地构造查询:

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
投票

您需要指定

Route
类的哪个属性需要与
searchPattern
prefix
进行比较。您不能在您的场景中隐式执行
.ToString()


1
投票

我认为你必须有一个名为

ID
Name
的属性,你想将其与
searchPattern
进行比较,然后使用:

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

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

编辑:

看到问题的变化后,仍然无法在该查询中使用

ToString()
方法,因为它无法转换为SQL语句。

现在,您有两个选择:

第一个:(我不确定是否适用,取决于可疑的数据大小),在调用

ToList()
扩展之前尝试使用
Where
扩展从数据库加载所有记录。 这应该可以很好地工作,但可能会导致巨大的表出现问题。

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


1
投票

ToString()
较新版本的实体框架支持(从版本 6.1 开始)

请参阅 EF 6.1 的发行说明

EF6.1 中有什么

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

  • 支持 LINQ 查询中的 .ToString、String.Concat 和枚举 HasFlags。

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


0
投票

这篇文章这篇文章可能会提供一些帮助。请注意,第二个链接中建议的方法不适用于 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 );
}

0
投票

这是一个棘手的解决方案,你可以像这样连接:key是一个字符串属性,key是一个int?,它不是最好的性能解决方案,但它有效

    .Select(x => new Balance {
 Amount = x.Gem_Amount ?? 0,
 Balance = balance,
 Key = "" +(int)x.Key
 }).ToList();
© www.soinside.com 2019 - 2024. All rights reserved.