動的LINQクエリを使用して、クラス内のすべてのプロパティの一部のテキストを検索したいと思います。次の関数を使用して式を作成しています。プロパティ名と検索テキストをメソッドに渡しています。そのメソッドでは、プロパティタイプが文字列の場合、正常に機能しています。プロパティタイプがint、DateTime、GUIDの場合。その後、それは機能していません。
ご存知のように、要素の配列または文字列に対してのみ、Containsメソッドを使用します。プロパティの値を文字列にキャストする必要があると考えています。それを行う方法は?説明付きのソリューションは完全なヘルプです。
私はからコードを収集し、この 。
public static Expression<Func<T, bool>> ContainsExp<T>(string propertyName, string contains)
{
var parameterExp = Expression.Parameter(typeof(T), "type");
var propertyExp = Expression.Property(parameterExp, propertyName);
MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var someValue = Expression.Constant(contains, typeof(string));
var containsMethodExp = Expression.Call(propertyExp, method, someValue);
return Expression.Lambda<Func<T, bool>>(containsMethodExp, parameterExp);
}
まあ、あなたはおそらくエンティティへのlinqでToString()
を使用ToString()
ことが不可能であることを知っています。
したがって、次の質問は:他の型を文字列に変換するにはどうすればよいですか?
数値の場合 、あなたはSqlFunctions.StringConvert
を持っていますが、それはdouble?
オーバーロードしか持っていませdouble?
そしてdecimal?
日時については、使用して何かを見つけることがSqlFunctions.StringConvert
適用した後SqlFunctions.DatePart
あなたにDateTime
(これはおそらく手段に少なくとも3コールSqlFunctions.DatePart
、年、月、日)
Guidの場合、直接実行する方法はないと思います。 1つの方法(SQL Serverを使用している場合はdbレベル)は、計算された列を持つことです。計算された列は、GUIDのvarchar変換表現を格納できます。多分もっと良い方法があります。
とにかく、これは少なくともstring
だけでなくinteger
でも機能するサンプルです:
public static Expression<Func<T, bool>> ContainsExp<T>(string propertyName, string contains)
{
//first, get the type of your property
var propertyType = typeof(T).GetProperty(propertyName).PropertyType;
//no change
var parameterExp = Expression.Parameter(typeof (T), "type");
Expression propertyExp = Expression.Property(parameterExp, propertyName);
//if property's type is int
if (propertyType == typeof (int))
{
//convert your Expression to a nullable double (or nullable decimal),
//so that you can use SqlFunctions.StringConvert
propertyExp = Expression.Convert(propertyExp, typeof (double?));
//get the SqlFunctions.StringConvert method for nullable double
var stringConvertMethod = typeof (SqlFunctions).GetMethod("StringConvert", new[] {typeof (double?)});
//call StringConvert on your converted expression
propertyExp = Expression.Call(stringConvertMethod , propertyExp);
}
//no change
var method = typeof (string).GetMethod("Contains", new[] {typeof (string)});
var someValue = Expression.Constant(contains, typeof (string));
var containsMethodExp = Expression.Call(propertyExp, method, someValue);
return Expression.Lambda<Func<T, bool>>(containsMethodExp, parameterExp);
}
public static IQueryable<T> FieldsContains<T>(this IQueryable<T> query, List<string> fileds, string searchValue)
{
Expression predicate = null;
var parameterExpression = Expression.Parameter(typeof(T), "type");
foreach (string field in fileds)
{
var next = GetFieldContainsExpression<T>(parameterExpression, field, searchValue);
if (predicate == null)
{
predicate = next;
}
else
{
predicate = Expression.Or(predicate, next);
}
}
var lambda = Expression.Lambda<Func<T, bool>>(predicate, parameterExpression);
return query.Where(lambda);
}
private static Expression GetFieldContainsExpression<T>(ParameterExpression parameterExpression, string field, string value)
{
var propertyType = typeof(T).GetProperty(field).PropertyType;
Expression propertyExpression = Expression.Property(parameterExpression, field);
var filterValue = Expression.Constant(value);
var method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
//call toString first to ignore type errors(datetime, int ...)
var toStringExpression = Expression.Call(propertyExpression, "ToString", Type.EmptyTypes);
var containsExpression = Expression.Call(toStringExpression, method, filterValue);
return containsExpression;
}