2012-02-02 77 views
0

我有下面的代码:如何使这个查询在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到SQL但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支持的操作受限于设计。 – 2012-02-02 20:44:22

+0

只是略读这个问题,我想知道你是否想要看看LINQKit中的DynamicQuery或PredicateBuilder - 前者@ http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part -1-using-the-linq-dynamic-query-library.aspx和后者@ http://www.albahari.com/nutshell/linqkit.aspx – 2012-02-05 07:32:25

回答

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的泛型类型的实体的成员。另一个有用的事情是,在针对此方法进行编码时,当您开始为第二个参数键入lambda表达式时,intellisense将向您显示实体的成员。在方法本身中,当我对属性值和请求值调用.ToLower()以使比较大小写不敏感时,我为字符串类型添加了一个异常。对于非字符串类型,这些值按“原样”进行比较,即不进行任何修改。 上面的例子是完整的 - 您可以将其复制并粘贴到控制台应用程序项目(尽管您需要引用EntityFramework.dll)。 希望这有助于。

0

试试这个:

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; 
} 

基本上,如果属性是字符串,则不会调用ToString()方法。

希望它有帮助。

+0

另一种选择是始终使用属性的类型。如果它是一个字符串,则将它们设置为较低值(搜索值和表达式中的属性)。如果不是,请尝试将字符串解析为属性类型。如果你不能解析它,那么返回false。如果可以解析它,请在表达式中使用该值;) – ivowiblo 2012-02-04 04:47:17

+0

这就是我在我提出的解决方案中所做的。在非字符串列上调用.ToString()也不起作用 - 您将看到相同的异常,说.ToString()不受支持。 – Pawel 2012-02-04 20:44:13

+0

但是你的解决方案不是动态的,它不是一样的 – ivowiblo 2012-02-05 05:19:42