我正在尝试构建一个动态的Linq to Sql查询,除了调用SqlMethods.Like方法之外,它还运行良好。我的代码在下面,生成的linq语句的主体如下所示:
Body = {((((log.ClientCode == "C1") OrElse
(log.ClientCode == "C2")) AndAlso
(log.Source == "S1")) AndAlso Like("Message", "%1%"))}
正如你所看到的,它试图打电话给#34;喜欢"没有SqlMethods类。知道我做错了什么吗?
public IEnumerable<ILog> Get(int pageNumber, int pageCount,
List<string> clientCodes, List<string> sources, List<LogLevel> logLevels,
string messageContains, string userNameContains,
DateTime? dateStart, DateTime? dateEnd)
{
var expressions = new List<Expression>();
ParameterExpression pe = Expression.Parameter(typeof(Data.Logging.Log), "log");
if (clientCodes != null && clientCodes.Count > 0)
{
expressions.Add(CreateClientCodeExpression(pe, clientCodes));
}
if (sources != null && sources.Count > 0)
{
expressions.Add(CreateSourceExpression(pe, sources));
}
if (logLevels != null && logLevels.Count > 0)
{
expressions.Add(CreateLogLevelExpression(pe, logLevels));
}
if (!string.IsNullOrWhiteSpace(messageContains))
{
expressions.Add(CreateMessageExpression(pe, messageContains));
}
Expression exp = null;
if (expressions.Count > 0)
{
exp = expressions[0];
}
for (var i = 1; i < expressions.Count; i++)
{
exp = Expression.AndAlso(exp, expressions[i]);
}
var predicate = Expression.Lambda<Func<Data.Logging.Log, bool>>(exp, pe);
var results = DbContext.Logs.Where(predicate).ToList();
foreach (var result in results)
{
yield return ConvertDbLogToLog(result);
}
}
private Expression CreateClientCodeExpression(ParameterExpression pe, List<string> clientCodes)
{
Expression result = null;
clientCodes.ForEach(cc =>
{
MemberExpression me = Expression.Property(pe, "ClientCode");
ConstantExpression ce = Expression.Constant(cc);
if (result == null) { result = Expression.Equal(me, ce); }
else { result = Expression.OrElse(result, Expression.Equal(me, ce)); }
});
return result;
}
private Expression CreateSourceExpression(ParameterExpression pe, List<string> sources)
{
Expression result = null;
sources.ForEach(s =>
{
MemberExpression me = Expression.Property(pe, "Source");
ConstantExpression ce = Expression.Constant(s);
if (result == null) { result = Expression.Equal(me, ce); }
else { result = Expression.OrElse(result, Expression.Equal(me, ce)); }
});
return result;
}
private Expression CreateLogLevelExpression(ParameterExpression pe, List<LogLevel> logLevels)
{
Expression result = null;
logLevels.ForEach(l =>
{
MemberExpression me = Expression.Property(pe, "LogLevel");
ConstantExpression ce = Expression.Constant(l.ToString());
if (result == null) { result = Expression.Equal(me, ce); }
else { result = Expression.OrElse(result, Expression.Equal(me, ce)); }
});
return result;
}
private MethodCallExpression CreateMessageExpression(ParameterExpression pe, string message)
{
return Expression.Call(typeof(SqlMethods).GetMethod("Like", new[] { typeof(string), typeof(string) }),
Expression.Constant("Message"), Expression.Constant(string.Format("%{0}%", message)));
}
答案 0 :(得分:1)
实际上,'Contains'运算符并不总是足够的。例如,如果你想搜索这样的东西:'first%last'。字符串中的'%'将按字面意思取代而不是预期的通配符。要使用'SqlMethods.Like'运算符,您可以使用以下命令:
public static MethodCallExpression Like(this ParameterExpression pe, string value)
{
var prop = Expression.Property(pe, pe.Name);
return Expression.Call(typeof(SqlMethods), "Like", null, prop, Expression.Constant(value));
}
答案 1 :(得分:-2)
您可以跳过Like
调用,并使用Contains
,Linq-to-SQL和Linq-to-Entities都正确转换为LIKE
语句。你甚至可以保存报价! (顺便说一下,你做错了。)
private MethodCallExpression CreateMessageExpression(ParameterExpression pe, string message)
{
return Expression.Call(Expression.Property(pe, "Message"), "Contains", null, Expression.Constant(message));
}