Dil*_*lip 0 c# linq collections lambda c#-4.0
我正在尝试从IQueryable对象创建一个自定义集合,我试图执行一个select语句,但是获取错误无法转换为存储表达式.我是Lambda Expression的新手.请帮我解决这个问题.
在c.Event.FirstUpper()行获取错误
public static string FirstCharToUpper(string input)
{
if (String.IsNullOrEmpty(input))
return string.Empty;
var trimmed = input.Trim();
return trimmed.First().ToString().ToUpper() + trimmed.Substring(1);
}
public static Expression<Func<string, string>> GetFirstCaseToUpperExpression()
{
var expression = NJection.LambdaConverter.Fluent.Lambda.TransformMethodTo<Func<string, string>>()
.From(() => StringFormatter.FirstCharToUpper)
.ToLambda();
return expression;
}
Run Code Online (Sandbox Code Playgroud)
调用表达式
return new List<LoggerModel>(
logDB.PELoggers
.Where(c => (c.SubscriberCode == SubscriberCode)).OrderByField(sortBy, ascendingOrder).Select(c => new LoggerModel()
{
DateTime = c.DateTime.Value,
Event = c.Event.FirstUpper()
})
Run Code Online (Sandbox Code Playgroud)
我想你正在使用Entity Framework或一个熟悉的O/R映射器.
想想你在这里做了什么:你正在编写一个应该针对你的数据库执行的LINQ查询.为此,它会将您的LINQ查询转换为SQL查询,然后对您的数据库执行.
但是FirstCharToUpper()代码中的自定义方法.您的数据库对此一无所知,因此您的O/R映射器的LINQ提供程序无法将其转换为SQL中有意义的任何内容,因此您会收到错误.
因此,您需要做的是首先对数据库"完成"查询以将结果保存在内存中,然后应用任何进一步的处理,这些处理只能在内存集合中的代码边界内完成.
您可以通过.AsEnumerable()在使用自定义表达式执行select之前插入LINQ查询来执行此操作:
logDB.PELoggers
.Where(c => (c.SubscriberCode == SubscriberCode))
.OrderByField(sortBy, ascendingOrder)
.AsEnumerable()
.Select(c => new LoggerModel()
{
DateTime = c.DateTime.Value,
Event = c.Event.FirstUpper()
})
Run Code Online (Sandbox Code Playgroud)
调用时AsEnumerable(),将执行针对您的数据库的查询,并将结果复制到IEnumerable内存中.在Select()事后将现在已经对内存中的集合对数据库执行了,而不是,因此可以使用自定义FirstCharToUpper()的方法.
根据您的评论进行编辑:
以上所有内容仍然有效,但在评论中,您说您的功能需要返回IQueryable.在您的情况下,您的FirstCharToUpper()方法正在做的非常简单,LINQ到实体提供程序确实支持像ToUpper和的方法Substring.所以我建议简单地删除你的帮助器方法,而不是使用Entity Framework可以转换为有效SQL的方法编写你的LINQ查询来做到这一点:
logDB.PELoggers
.Where(c => (c.SubscriberCode == SubscriberCode))
.OrderByField(sortBy, ascendingOrder)
.Select(c => new LoggerModel()
{
DateTime = c.DateTime.Value,
Event = c.Event.Substring(0, 1).ToUpper()
+ c.Event.Substring(1)
})
Run Code Online (Sandbox Code Playgroud)
这将导致SQL查询已经返回Event中的内容,其中包含数据库中的大写首字母.
为了支持IsNullOrEmpty检查和Trim你正在做的事情(LINQ-to-Entities也支持)我建议将lambda语法更改为LINQ查询语法,这样你就可以使用let语句进行修剪,这样可以使代码更清晰:
from c in logDB.PELoggers
let trimmedEvent = c.Event.Trim()
where c.SubscriberCode == SubscriberCode
select new LoggerModel()
{
DateTime = c.DateTime.Value,
Event = !string.IsNullOrEmpty(trimmedEvent)
? trimmedEvent.Substring(0, 1).ToUpper()
+ trimmedEvent.Substring(1)
: string.Empty
};
Run Code Online (Sandbox Code Playgroud)
如果您不希望在LINQ查询中完成此操作,则需要在稍后执行对DB的查询时执行大写,例如在将显示数据的视图中.或者一个选项可以是在您的Event属性设置器中应用大写LoggerModel:
public class LoggerModel
{
// ...
private string event;
public string Event
{
get { return event; }
set { event = FirstCharToUpper(value); }
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
但是没有办法让自定义函数在LINQ-to-Entities查询中工作.