实体框架无法识别我的将路由对象转换为指定字符串的 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 中不支持的异常。
有什么解决办法吗?
您无法在客户端执行此操作 (
ToString
)。
您必须创建将进行评估的 SQL 函数 - 它可以仅对您的位置进行字符串连接(我相信它是相关实体),或者您可以在自定义函数中进行整个测试。然后,您可以将该函数导入到实体模型 (EDMX) 中并创建
EdmFunctionAttribute
来调用它 - MSDN。
实体框架无法识别我的将路由对象转换为指定字符串的 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));
}
您需要指定
Route
类的哪个属性需要与 searchPattern
或 prefix
进行比较。您不能在您的场景中隐式执行 .ToString()
。
我认为你必须有一个名为
ID
或 Name
的属性,你想将其与 searchPattern
进行比较,然后使用:
.Where(x => searchPattern == null || x.Name.Contains(searchPattern));
因为我假设 x 展示了一个实体,所以,你想如何将实体的名称本身与搜索模式进行比较?
编辑:
看到问题的变化后,仍然无法在该查询中使用
ToString()
方法,因为它无法转换为SQL语句。
现在,您有两个选择:
第一个:(我不确定是否适用,取决于可疑的数据大小),在调用
ToList()
扩展之前尝试使用 Where
扩展从数据库加载所有记录。
这应该可以很好地工作,但可能会导致巨大的表出现问题。
第二个:你必须创建一个存储过程并将逻辑移至数据库。
ToString()
较新版本的实体框架支持(从版本 6.1 开始)
请参阅 EF 6.1 的发行说明:
EF6.1 中有什么
EF6.1 添加了以下新功能:
[...]
- 支持 LINQ 查询中的 .ToString、String.Concat 和枚举 HasFlags。
(嗯,这个问题已经有几年了,但也许这些信息可能对其他人有帮助...... 另请参阅相关问题How to use ToString SelectListItem with Entity Framework?)
这篇文章和这篇文章可能会提供一些帮助。请注意,第二个链接中建议的方法不适用于 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 );
}
这是一个棘手的解决方案,你可以像这样连接:key是一个字符串属性,key是一个int?,它不是最好的性能解决方案,但它有效
.Select(x => new Balance {
Amount = x.Gem_Amount ?? 0,
Balance = balance,
Key = "" +(int)x.Key
}).ToList();