2012-02-02 14 views
0

私は次のコードにしている:それはSQLにLINQで動作しますこのクエリをLINQ to Entitiesで動作させるにはどうすればよいですか?

private static bool DoesColValueExist<T>(IQueryable dataToSearchIn, string colName, string colValue) 
{ 
    int noOfClients = 1; 
    Type type = typeof(T); 
    if (colValue != "" && colName != "") 
    { 
     var property = type.GetProperty(colName); 
     var parameter = Expression.Parameter(type, "p"); 
     var propertyAccess = Expression.MakeMemberAccess(parameter, property); 
     Expression left = Expression.Call(propertyAccess, typeof(object).GetMethod("ToString", System.Type.EmptyTypes)); 
     left = Expression.Call(left, typeof(string).GetMethod("ToLower", System.Type.EmptyTypes)); 
     Expression right = Expression.Constant(colValue.ToLower(), typeof(string)); 
     MethodInfo method = typeof(string).GetMethod("Equals", new[] { typeof(string) }); 
     Expression searchExpression = Expression.Call(left, method, right); 


     MethodCallExpression whereCallExpression = Expression.Call(
      typeof(Queryable), 
      "Where", 
      new Type[] { type }, 
      dataToSearchIn.Expression, 
      Expression.Lambda<Func<T, bool>>(searchExpression, new ParameterExpression[] { parameter })); 
     var searchedData = dataToSearchIn.Provider.CreateQuery(whereCallExpression); 
     noOfClients = searchedData.Cast<T>().Count(); 

     if (noOfClients == 0) 
      return false; 
     else 
      return true; 
    } 
    return true; 
} 

が、LINQをエンティティに、私はエラーを取得する:エンティティへ

LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression.

+0

どのような列の種類ですか?彼らは弦ではありませんか? 'colValue'を適切な型に変換して比較するのはどうですか? L2Eがサポートする操作は、設計によって制限されています。 –

+0

LINQKitのDynamicQueryまたはPredicateBuilder(以前の@ http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part)を見たいと思うかもしれないのか疑問に思っています。 -1-using-linq-dynamic-query-library.aspxと後者@ http://www.albahari.com/nutshell/linqkit.aspx –

答えて

1

LINQのは.ToString()メソッドをサポートしていません。 。文字列でない型に対して文字列の比較を使用するのがよいかどうかもわかりません。しかし、すべてが失われるわけではありません。私は、次の解決策を考え出した:

public partial class MyEntity 
{ 
    public int ID { get; set; } 
    public int Type { get; set; } 
    public string X { get; set; } 
} 

public class MyContext : DbContext 
{ 
    public DbSet<MyEntity> Entities { get; set; } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Database.SetInitializer(new DropCreateDatabaseIfModelChanges<MyContext>()); 

     using (var ctx = new MyContext()) 
     { 
      if (!ctx.Entities.Any()) 
      { 
       ctx.Entities.Add(new MyEntity() { ID = 1, Type = 2, X = "ABC" }); 
       ctx.SaveChanges(); 
      } 

      Console.WriteLine(DoesColValueExist(ctx.Entities, e => e.X, "aBc")); 
      Console.WriteLine(DoesColValueExist(ctx.Entities, e => e.X, "aBcD")); 
      Console.WriteLine(DoesColValueExist(ctx.Entities, e => e.Type, 2)); 
      Console.WriteLine(DoesColValueExist(ctx.Entities, e => e.Type, 5)); 

     } 
    } 

    private static bool DoesColValueExist<TEntity, TProperty>(IQueryable<TEntity> dataToSearchIn, Expression<Func<TEntity, TProperty>> property, TProperty colValue) 
    { 

     var memberExpression = property.Body as MemberExpression; 
     if (memberExpression == null || !(memberExpression.Member is PropertyInfo)) 
     { 
      throw new ArgumentException("Property expected", "property"); 
     } 

     Expression left = property.Body; 
     Expression right = Expression.Constant(colValue, typeof(TProperty)); 
     if (typeof(TProperty) == typeof(string)) 
     { 
      MethodInfo toLower = typeof(string).GetMethod("ToLower", new Type[0]); 
      left = Expression.Call(left, toLower); 
      right = Expression.Call(right, toLower); 
     } 

     Expression searchExpression = Expression.Equal(left, right); 
     var lambda = Expression.Lambda<Func<TEntity, bool>>(Expression.Equal(left, right), new ParameterExpression[] { property.Parameters.Single() }); 

     return dataToSearchIn.Where(lambda).Any();     
    } 
} 

それについての素晴らしい事は、それが文字列ベースのソリューションよりも安全でより多くの種類があるということです - パラメータの値は、プロパティの値と同じである必要があります。このプロパティは、最初のパラメータとして渡されたIQueryable'1のジェネリック型であるエンティティのメンバでなければなりません。もう1つの便利なことは、このメソッドに対してコーディングするときに、intellisenseが、2番目のパラメータのラムダ式の入力を開始するときに、エンティティのメンバーを表示するということです。メソッド自体で、プロパティの値と要求された値の両方で.ToLower()を呼び出すと、大文字と小文字を区別しないようにするために、文字列型の例外が追加されました。非文字列タイプの場合、値は「そのまま」、すなわち何も変更されずに比較される。 上記の例は完了です。コンソールアプリケーションプロジェクトにコピーして貼り付けることができます(EntityFramework.dllを参照する必要があります)。 これが役立つことを願っています。プロパティが文字列であるならば、それはToString()メソッドを呼び出すことはありませんが、基本的に

private static bool DoesColValueExist<T>(IQueryable dataToSearchIn, string colName, string colValue) 
{ 
    int noOfClients = 1; 
    Type type = typeof(T); 
    if (colValue != "" && colName != "") 
    { 
     var property = type.GetProperty(colName); 
     var parameter = Expression.Parameter(type, "p"); 
     var propertyAccess = Expression.MakeMemberAccess(parameter, property); 
     Expression left = property.PropertyType == typeof(string) ? propertyAccess : Expression.Call(propertyAccess, typeof(object).GetMethod("ToString", System.Type.EmptyTypes)); 
     left = Expression.Call(left, typeof(string).GetMethod("ToLower", System.Type.EmptyTypes)); 
     Expression right = Expression.Constant(colValue.ToLower(), typeof(string)); 
     MethodInfo method = typeof(string).GetMethod("Equals", new[] { typeof(string) }); 
     Expression searchExpression = Expression.Call(left, method, right); 


     MethodCallExpression whereCallExpression = Expression.Call(
      typeof(Queryable), 
      "Where", 
      new Type[] { type }, 
      dataToSearchIn.Expression, 
      Expression.Lambda<Func<T, bool>>(searchExpression, new ParameterExpression[] { parameter })); 
     var searchedData = dataToSearchIn.Provider.CreateQuery(whereCallExpression); 
     noOfClients = searchedData.Cast<T>().Count(); 

     if (noOfClients == 0) 
      return false; 
     else 
      return true; 
    } 
    return true; 
} 

0

はこれを試してみてください。

希望します。

+0

もう1つのオプションは、常にプロパティの型を使用することです。それが文字列の場合は、両方を低くします(検索する値と式のプロパティ)。そうでない場合は、文字列をプロパティタイプに解析してみてください。解析できない場合は、falseを返します。解析することができれば、その値を式に使用します;) – ivowiblo

+0

これは私が提案した解決策で行ったことです。また、文字列以外の列でも.ToString()を呼び出すことはできません.ToToString()はサポートされていないという同じ例外が表示されます。 – Pawel

+0

あなたの解決策は動的ではありません。同じではありません – ivowiblo

関連する問題