Question

I'm using the Dynamic Linq with Linq to Entities

So, I tested the normal List<Person> with this code and everything's work:

 List<Person> per = new List<Person>();
 per.Add(new Person { IdNo = "1", LastName = "test", MiddleName = "go", FirstName = "let" });
 per.Add(new Person { IdNo = "2", LastName = "hope", MiddleName = "is", FirstName = "way" });
 per.Add(new Person { IdNo = "3", LastName = "must", MiddleName = "be", FirstName = "human" });
 per.Add(new Person { IdNo = "4", LastName = "thing", MiddleName = "anywhere", FirstName = "can" });
 per.Add(new Person { IdNo = "5", LastName = "bird", MiddleName = "fly", FirstName = "away" });

 List<object> paramObjects = new List<object>();
 List<string> fields = new List<string>();
 fields.Add("IdNo == @0");
 paramObjects.Add("1");

 fields.Add("or (LastName + \", \" + MiddleName + \" \" + FirstName).Contains(@1)");
 paramObjects.Add("m");

 var where = string.Join(" ", fields.ToArray());
 var toParam = paramObjects.ToArray();

 var query = per.AsQueryable().Where(where, toParam).ToList();

and when I'm in Linq To Entities approach.

using(var con = new DbContext())
{
   var query = con.Person.Where(where, toParam).ToList();
}

I got this error:

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

My question is:

How to Concat the string using the Linq To Entities base in my example using the Dynamic Linq? Anyone can help me?

Was it helpful?

Solution

  • Option 1:

    Change the line...

    fields.Add("or (LastName + \", \" + MiddleName + \" \" + FirstName).Contains(@1)");
    

    ...to

    fields.Add("or string.Concat(LastName, \", \", MiddleName, \" \", FirstName).Contains(@1)");
    
  • Option 2:

    Open the Dynamic.cs file of the Dynamic LINQ library, search for "GenerateStringConcat" in that file. You should find this method:

    Expression GenerateStringConcat(Expression left, Expression right) {
        return Expression.Call(
            null,
            typeof(string).GetMethod("Concat",
                new[] { typeof(object), typeof(object) }),
            new[] { left, right });
    }
    

    Change the object parameter types to string, that is:

    Expression GenerateStringConcat(Expression left, Expression right) {
        return Expression.Call(
            null,
            typeof(string).GetMethod("Concat",
                new[] { typeof(string), typeof(string) }),
            new[] { left, right });
    }
    

Keep in mind that Dynamic LINQ is not a special "LINQ-to-Entities library", but a general library for IQueryable. There might be Queryable providers that support string.Concat(object, object) with the general object parameter, but LINQ-to-Entities does not. It only supports the string parameter versions of string.Concat. Looking through the Dynamic LINQ file when GenerateStringConcat is actually called (only once) I believe the change above is safe as long as you only want to use the library with LINQ-to-Entities/Entity Framework.

Edit

Option 1 does not work because Concat gets more than four string parameters in the example. It only works up to four parameters because string.Concat has an overload with four explicit string parameters. It doesn't seem to be possible to use the overload with the array parameter params string[] in Dynamic LINQ.

OTHER TIPS

I had the same problem but with NHibernate, my solution was to modify GenerateStringConcat Method

I change this:

static Expression GenerateStringConcat(Expression left, Expression right)
    {   
        return Expression.Call(
            null,
            typeof(string).GetMethod("Concat", new[] { typeof(object), typeof(object) }),
            new[] { left, right });
    }

For this:

static Expression GenerateStringConcat(Expression left, Expression right)
    {            
        return Expression.Add(
            left,
            right,
            typeof(string).GetMethod("Concat", new[] { typeof(object), typeof(object) })
        );
    }

He has worked quite well :)

Change

 var where = string.Join(" ", fields.ToArray());

to

string where = string.Empty;
foreach(var f in fields)
{
    where += f + " "; 
}

where = where.Trim();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top