How to optimize LINQ expressions? - optimization

On a project built with .NET 3.5, I am using LINQ expressions to dynamically generate code at runtime. The LINQ expressions are compiled using the Compile method and stored for later use as predicates with LINQ to objects.
The expressions are sometimes quite complicated and difficult to debug.
Below is an example of an expression viewed through the debugger visualizer in Visual Studio.
{request
=> (Invoke(workEnvelopeHead
=> (workEnvelopeHead.Method = value(Wombl.Scenarios.CannedResponses+<>c_DisplayClass58).pipeline),
request.WorkEnvelope.Head)
And Invoke(body =>
Invoke(value(Wombl.Scenarios.CannedResponses+<>c_DisplayClass78).isMatch,
body.SingleOrDefault()),Convert(request.WorkEnvelope.Body.Any)))}
I would like to be able to optimize expressions like the above so that the value(Wombl.Scenarios.CannedResponses+<>c__DisplayClass58).pipeline expression is replaced with a constant that is the variable's value.
In this particular case, value(Wombl.Scenarios.CannedResponses+<>c__DisplayClass58).pipeline is a reference in the lambda to a variable in the parent scope. Something like:
var pipeline = "[My variable's value here]";
// My lambda expression here, which references pipeline
// Func<RequestType, bool> predicate = request => ........ workEnvelopeHead.Method == pipeline ..........
The original expression, optimized ought to look like:
{request => (Invoke(workEnvelopeHead =>
(workEnvelopeHead.Method = "[My variable's value here]",
request.WorkEnvelope.Head) And Invoke(body => > Invoke(value(Wombl.Scenarios.CannedResponses+<>c__DisplayClass78).isMatch,
body.SingleOrDefault()),Convert(request.WorkEnvelope.Body.Any)))}
How can I make such optimizations at runtime to the LINQ expression, before compiling?

So I went ahead and wrote an expression visitor that replaces the variable references with the actual value. It wasn't so hard to do after all.
Usage:
var simplifiedExpression = ExpressionOptimizer.Simplify(complexExpression);
The class:
It inherits from ExpressionVisitor which came from the code samples on this page because in .NET 3.0 it is internal. In .NET 4.0 the class is public but might require some changes to this class.
public sealed class ExpressionOptimizer : ExpressionVisitor
{
private ExpressionOptimizer()
{
}
#region Methods
public static Expression<TDelegate> Simplify<TDelegate>(Expression<TDelegate> expression)
{
return expression == null
? null
: (Expression<TDelegate>) new ExpressionOptimizer().Visit(expression);
}
private static bool IsPrimitive(Type type)
{
return type.IsPrimitive
|| type.IsEnum
|| type == typeof (string)
|| type == typeof (DateTime)
|| type == typeof (TimeSpan)
|| type == typeof (DateTimeOffset)
|| type == typeof (Decimal)
|| typeof(Delegate).IsAssignableFrom(type);
}
protected override Expression VisitMemberAccess(MemberExpression memberExpression)
{
var constantExpression = memberExpression.Expression as ConstantExpression;
if (constantExpression == null || !IsPrimitive(memberExpression.Type))
return base.VisitMemberAccess(memberExpression);
// Replace the MemberExpression with a ConstantExpression
var constantValue = constantExpression.Value;
var propertyInfo = memberExpression.Member as PropertyInfo;
var value = propertyInfo == null
? ((FieldInfo) memberExpression.Member).GetValue(constantValue)
: propertyInfo.GetValue(constantValue, null);
return Expression.Constant(value);
}
#endregion
}

Related

How can I use coalescing operator in Haxe?

As I mentioned in the question,
How can I use coalescing operator in Haxe?
Haxe does not have a null coalescing operator like C#'s ??.
That being said, it's possible to achieve something similar with macros. It looks like somebody has already written a library that does exactly this a few years ago. Here's an example from its readme:
var s = Sys.args()[0];
var path = s || '/default/path/to/../';
It uses the existing || operator because macros can not introduce entirely new syntax.
However, personally I would probably prefer a static extension like this:
class StaticExtensions {
public static function or<T>(value:T, defaultValue:T):T {
return value == null ? defaultValue : value;
}
}
using StaticExtensions;
class Main {
static public function main() {
var foo:String = null;
trace(foo.or("bar")); // bar
}
}
Instead of making your own, you could also consider using the safety library, which has a number of additional static extensions for Null<T> and features for dealing with null in general.
Use this addon:
https://github.com/skial/nco
Then, type
var value = a || 'backup value';
instead of
var value = (a == null) ? 'backup value' : a;
You can also utilize abstracts instead of macros for this purpose
class Test {
static function main() {
trace("Haxe is great!");
var s:Ory<String> = "hi!";
trace(s || "I don't get picked");
s = null;
trace(s || "I get picked");
trace(s + "!");
}
}
#:forward abstract Ory<T>(T) from T to T {
#:op(a||b) public inline function or(b:T):Ory<T> {
return this != null ? this : b;
}
}

Why Does Kotlin/JS Return Different Results for === Than Does Kotlin/JVM?

Given this code:
val value = "something"
println(value.toUpperCase().toLowerCase() == value) // prints true
println(value.toUpperCase().toLowerCase() === value) // prints false
On Kotlin/JVM 1.3.40, I get:
true
false
On Kotlin/JS 1.3.40, I get:
true
true
I would expect the same results on both, and I would expect the Kotlin/JVM results overall (as I should have different String objects).
Why am I getting different results based on runtime environment?
This is because of how the runtime handles it.
On the JVM, == maps to equals, and === maps to == (identity checking), as outlined here. Meanwhile, JavaScript's equals operators are weirder. If you decompile your code, you get this with JS:
kotlin.kotlin.io.output.flush();
if (typeof kotlin === 'undefined') {
throw new Error("Error loading module 'moduleId'. Its dependency 'kotlin' was not found. Please, check whether 'kotlin' is loaded prior to 'moduleId'.");
}
var moduleId = function (_, Kotlin) {
'use strict';
var equals = Kotlin.equals;
var println = Kotlin.kotlin.io.println_s8jyv4$;
function main(args) {
var value = 'something';
println(equals(value.toUpperCase().toLowerCase(), value)); // NOTE: equals
println(value.toUpperCase().toLowerCase() === value); // NOTE: ===
}
_.main_kand9s$ = main;
main([]);
Kotlin.defineModule('moduleId', _);
return _;
}(typeof moduleId === 'undefined' ? {} : moduleId, kotlin);
kotlin.kotlin.io.output.buffer;
Now, if you consider the equivalent Java code (slightly shortened and without Kotlin):
public static void main(String[] args){
String value = "something";
System.out.println(value.toUpperCase().toLowerCase().equals(value));
System.out.println(value.toUpperCase().toLowerCase() == value);
}
toUpperCase().toLowerCase() creates a new object, which breaks the == comparison, which is identity checking.
While === is outlined as identity checking as well, a === b is true if a and b are strings that contain the same characters. As you can tell from the decompiled Kotlin code, Kotlin.JS compiles to primitive Strings, not String objects. Because of that, the === in JS will return true when you're dealing with primitive strings.
In JavaScript there are both primitive strings and string objects (see e.g. "Distinction between string primitives and String objects" in https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String).
value.toUpperCase().toLowerCase() === value in Kotlin/JS compiles to value.toUpperCase().toLowerCase() === value in JavaScript (as you can verify by looking at the "Generated JavaScript code" tab at https://try.kotlinlang.org/). value.toUpperCase().toLowerCase() returns a primitive string. === on primitive strings is normal equality.

Dynamic Anonymous type in Razor causes RuntimeBinderException

I'm getting the following error:
'object' does not contain a definition for 'RatingName'
When you look at the anonymous dynamic type, it clearly does have RatingName.
I realize I can do this with a Tuple, but I would like to understand why the error message occurs.
Anonymous types having internal properties is a poor .NET framework design decision, in my opinion.
Here is a quick and nice extension to fix this problem i.e. by converting the anonymous object into an ExpandoObject right away.
public static ExpandoObject ToExpando(this object anonymousObject)
{
IDictionary<string, object> anonymousDictionary = new RouteValueDictionary(anonymousObject);
IDictionary<string, object> expando = new ExpandoObject();
foreach (var item in anonymousDictionary)
expando.Add(item);
return (ExpandoObject)expando;
}
It's very easy to use:
return View("ViewName", someLinq.Select(new { x=1, y=2}.ToExpando());
Of course in your view:
#foreach (var item in Model) {
<div>x = #item.x, y = #item.y</div>
}
I found the answer in a related question. The answer is specified on David Ebbo's blog post Passing anonymous objects to MVC views and accessing them using dynamic
The reason for this is that the
anonymous type being passed in the
controller in internal, so it can only
be accessed from within the assembly
in which it’s declared. Since views
get compiled separately, the dynamic
binder complains that it can’t go over
that assembly boundary.
But if you think about it, this
restriction from the dynamic binder is
actually quite artificial, because if
you use private reflection, nothing is
stopping you from accessing those
internal members (yes, it even work in
Medium trust). So the default dynamic
binder is going out of its way to
enforce C# compilation rules (where
you can’t access internal members),
instead of letting you do what the CLR
runtime allows.
Using ToExpando method is the best solution.
Here is the version that doesn't require System.Web assembly:
public static ExpandoObject ToExpando(this object anonymousObject)
{
IDictionary<string, object> expando = new ExpandoObject();
foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(anonymousObject))
{
var obj = propertyDescriptor.GetValue(anonymousObject);
expando.Add(propertyDescriptor.Name, obj);
}
return (ExpandoObject)expando;
}
Instead of creating a model from an anonymous type and then trying to convert the anonymous object to an ExpandoObject like this ...
var model = new
{
Profile = profile,
Foo = foo
};
return View(model.ToExpando()); // not a framework method (see other answers)
You can just create the ExpandoObject directly:
dynamic model = new ExpandoObject();
model.Profile = profile;
model.Foo = foo;
return View(model);
Then in your view you set the model type as dynamic #model dynamic and you can access the properties directly :
#Model.Profile.Name
#Model.Foo
I'd normally recommend strongly typed view models for most views, but sometimes this flexibility is handy.
You can use the framework impromptu interface to wrap an anonymous type in an interface.
You'd just return an IEnumerable<IMadeUpInterface> and at the end of your Linq use .AllActLike<IMadeUpInterface>(); this works because it calls the anonymous property using the DLR with a context of the assembly that declared the anonymous type.
Wrote a console application and add Mono.Cecil as reference (you can now add it from NuGet), then write the piece of code:
static void Main(string[] args)
{
var asmFile = args[0];
Console.WriteLine("Making anonymous types public for '{0}'.", asmFile);
var asmDef = AssemblyDefinition.ReadAssembly(asmFile, new ReaderParameters
{
ReadSymbols = true
});
var anonymousTypes = asmDef.Modules
.SelectMany(m => m.Types)
.Where(t => t.Name.Contains("<>f__AnonymousType"));
foreach (var type in anonymousTypes)
{
type.IsPublic = true;
}
asmDef.Write(asmFile, new WriterParameters
{
WriteSymbols = true
});
}
The code above would get the assembly file from input args and use Mono.Cecil to change the accessibility from internal to public, and that would resolve the problem.
We can run the program in the Post Build event of the website. I wrote a blog post about this in Chinese but I believe you can just read the code and snapshots. :)
Based on the accepted answer, I have overridden in the controller to make it work in general and behind the scenes.
Here is the code:
protected override void OnResultExecuting(ResultExecutingContext filterContext)
{
base.OnResultExecuting(filterContext);
//This is needed to allow the anonymous type as they are intenal to the assembly, while razor compiles .cshtml files into a seperate assembly
if (ViewData != null && ViewData.Model != null && ViewData.Model.GetType().IsNotPublic)
{
try
{
IDictionary<string, object> expando = new ExpandoObject();
(new RouteValueDictionary(ViewData.Model)).ToList().ForEach(item => expando.Add(item));
ViewData.Model = expando;
}
catch
{
throw new Exception("The model provided is not 'public' and therefore not avaialable to the view, and there was no way of handing it over");
}
}
}
Now you can just pass an anonymous object as the model, and it will work as expected.
I'm going to do a little bit of stealing from https://stackoverflow.com/a/7478600/37055
If you install-package dynamitey you can do this:
return View(Build<ExpandoObject>.NewObject(RatingName: name, Comment: comment));
And the peasants rejoice.
The reason of RuntimeBinderException triggered, I think there have good answer in other posts. I just focus to explain how I actually make it work.
By refer to answer #DotNetWise and Binding views with Anonymous type collection in ASP.NET MVC,
Firstly, Create a static class for extension
public static class impFunctions
{
//converting the anonymous object into an ExpandoObject
public static ExpandoObject ToExpando(this object anonymousObject)
{
//IDictionary<string, object> anonymousDictionary = new RouteValueDictionary(anonymousObject);
IDictionary<string, object> anonymousDictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(anonymousObject);
IDictionary<string, object> expando = new ExpandoObject();
foreach (var item in anonymousDictionary)
expando.Add(item);
return (ExpandoObject)expando;
}
}
In controller
public ActionResult VisitCount()
{
dynamic Visitor = db.Visitors
.GroupBy(p => p.NRIC)
.Select(g => new { nric = g.Key, count = g.Count()})
.OrderByDescending(g => g.count)
.AsEnumerable() //important to convert to Enumerable
.Select(c => c.ToExpando()); //convert to ExpandoObject
return View(Visitor);
}
In View, #model IEnumerable (dynamic, not a model class), this is very important as we are going to bind the anonymous type object.
#model IEnumerable<dynamic>
#*#foreach (dynamic item in Model)*#
#foreach (var item in Model)
{
<div>x=#item.nric, y=#item.count</div>
}
The type in foreach, I have no error either using var or dynamic.
By the way, create a new ViewModel that is matching the new fields also can be the way to pass the result to the view.
Now in recursive flavor
public static ExpandoObject ToExpando(this object obj)
{
IDictionary<string, object> expandoObject = new ExpandoObject();
new RouteValueDictionary(obj).ForEach(o => expandoObject.Add(o.Key, o.Value == null || new[]
{
typeof (Enum),
typeof (String),
typeof (Char),
typeof (Guid),
typeof (Boolean),
typeof (Byte),
typeof (Int16),
typeof (Int32),
typeof (Int64),
typeof (Single),
typeof (Double),
typeof (Decimal),
typeof (SByte),
typeof (UInt16),
typeof (UInt32),
typeof (UInt64),
typeof (DateTime),
typeof (DateTimeOffset),
typeof (TimeSpan),
}.Any(oo => oo.IsInstanceOfType(o.Value))
? o.Value
: o.Value.ToExpando()));
return (ExpandoObject) expandoObject;
}
Using the ExpandoObject Extension works but breaks when using nested anonymous objects.
Such as
var projectInfo = new {
Id = proj.Id,
UserName = user.Name
};
var workitem = WorkBL.Get(id);
return View(new
{
Project = projectInfo,
WorkItem = workitem
}.ToExpando());
To accomplish this I use this.
public static class RazorDynamicExtension
{
/// <summary>
/// Dynamic object that we'll utilize to return anonymous type parameters in Views
/// </summary>
public class RazorDynamicObject : DynamicObject
{
internal object Model { get; set; }
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (binder.Name.ToUpper() == "ANONVALUE")
{
result = Model;
return true;
}
else
{
PropertyInfo propInfo = Model.GetType().GetProperty(binder.Name);
if (propInfo == null)
{
throw new InvalidOperationException(binder.Name);
}
object returnObject = propInfo.GetValue(Model, null);
Type modelType = returnObject.GetType();
if (modelType != null
&& !modelType.IsPublic
&& modelType.BaseType == typeof(Object)
&& modelType.DeclaringType == null)
{
result = new RazorDynamicObject() { Model = returnObject };
}
else
{
result = returnObject;
}
return true;
}
}
}
public static RazorDynamicObject ToRazorDynamic(this object anonymousObject)
{
return new RazorDynamicObject() { Model = anonymousObject };
}
}
Usage in the controller is the same except you use ToRazorDynamic() instead of ToExpando().
In your view to get the entire anonymous object you just add ".AnonValue" to the end.
var project = #(Html.Raw(JsonConvert.SerializeObject(Model.Project.AnonValue)));
var projectName = #Model.Project.Name;
I tried the ExpandoObject but it didn't work with a nested anonymous complex type like this:
var model = new { value = 1, child = new { value = 2 } };
So my solution was to return a JObject to View model:
return View(JObject.FromObject(model));
and convert to dynamic in .cshtml:
#using Newtonsoft.Json.Linq;
#model JObject
#{
dynamic model = (dynamic)Model;
}
<span>Value of child is: #model.child.value</span>

C# ‘dynamic’ cannot access properties from anonymous types declared in another assembly

Code below is working well as long as I have class ClassSameAssembly in same assembly as class Program.
But when I move class ClassSameAssembly to a separate assembly, a RuntimeBinderException (see below) is thrown.
Is it possible to resolve it?
using System;
namespace ConsoleApplication2
{
public static class ClassSameAssembly
{
public static dynamic GetValues()
{
return new
{
Name = "Michael", Age = 20
};
}
}
internal class Program
{
private static void Main(string[] args)
{
var d = ClassSameAssembly.GetValues();
Console.WriteLine("{0} is {1} years old", d.Name, d.Age);
}
}
}
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'object' does not contain a definition for 'Name'
at CallSite.Target(Closure , CallSite , Object )
at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
at ConsoleApplication2.Program.Main(String[] args) in C:\temp\Projects\ConsoleApplication2\ConsoleApplication2\Program.cs:line 23
I believe the problem is that the anonymous type is generated as internal, so the binder doesn't really "know" about it as such.
Try using ExpandoObject instead:
public static dynamic GetValues()
{
dynamic expando = new ExpandoObject();
expando.Name = "Michael";
expando.Age = 20;
return expando;
}
I know that's somewhat ugly, but it's the best I can think of at the moment... I don't think you can even use an object initializer with it, because while it's strongly typed as ExpandoObject the compiler won't know what to do with "Name" and "Age". You may be able to do this:
dynamic expando = new ExpandoObject()
{
{ "Name", "Michael" },
{ "Age", 20 }
};
return expando;
but that's not much better...
You could potentially write an extension method to convert an anonymous type to an expando with the same contents via reflection. Then you could write:
return new { Name = "Michael", Age = 20 }.ToExpando();
That's pretty horrible though :(
You could use [assembly: InternalsVisibleTo("YourAssemblyName")] to make you assembly internals visible.
I ran into a similair problem and would like to add to Jon Skeets answer that there is another option. The reason I found out was that I realized that many extension methods in Asp MVC3 uses anonymous classes as input to provide html attributes (new {alt="Image alt", style="padding-top: 5px"} =>
Anyway - those functions use the constructor of the RouteValueDictionary class. I tried that myself, and sure enough it works - though only the first level (I used a multi-level structure). SO - in code this would be:
object o = new {
name = "theName",
props = new {
p1 = "prop1",
p2 = "prop2"
}
}
SeparateAssembly.TextFunc(o)
//In SeparateAssembly:
public void TextFunc(Object o) {
var rvd = new RouteValueDictionary(o);
//Does not work:
Console.WriteLine(o.name);
Console.WriteLine(o.props.p1);
//DOES work!
Console.WriteLine(rvd["name"]);
//Does not work
Console.WriteLine(rvd["props"].p1);
Console.WriteLine(rvd["props"]["p1"]);
SO... What is really going on here? A peek inside the RouteValueDictionary reveals this code (values ~= o above):
foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(values))
object obj2 = descriptor.GetValue(values);
//"this.Add" would of course need to be adapted
this.Add(descriptor.Name, obj2);
}
SO - using TypeDescriptor.GetProperties(o) we would be able to get the properties and values despite the anonymous type being constructed as internal in a separate assembly! And of course this would be quite easy to extend to make it recursive. And to make an extension method if you wanted.
Hope this helps!
/Victor
Here is a rudimentary version of an extension method for ToExpandoObject that I'm sure has room for polishing.
public static ExpandoObject ToExpandoObject(this object value)
{
// Throw is a helper in my project, replace with your own check(s)
Throw<ArgumentNullException>.If(value, Predicates.IsNull, "value");
var obj = new ExpandoObject() as IDictionary<string, object>;
foreach (var property in value.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
obj.Add(property.Name, property.GetValue(value, null));
}
return obj as ExpandoObject;
}
[TestCase(1, "str", 10.75, 9.000989, true)]
public void ToExpandoObjectTests(int int1, string str1, decimal dec1, double dbl1, bool bl1)
{
DateTime now = DateTime.Now;
dynamic value = new {Int = int1, String = str1, Decimal = dec1, Double = dbl1, Bool = bl1, Now = now}.ToExpandoObject();
Assert.AreEqual(int1, value.Int);
Assert.AreEqual(str1, value.String);
Assert.AreEqual(dec1, value.Decimal);
Assert.AreEqual(dbl1, value.Double);
Assert.AreEqual(bl1, value.Bool);
Assert.AreEqual(now, value.Now);
}
Below solution worked for me in my console application projects
Put this [assembly: InternalsVisibleTo("YourAssemblyName")]
in \Properties\AssemblyInfo.cs of the separate project with function returning dynamic object.
"YourAssemblyName" is the assembly name of calling project. You can get that through Assembly.GetExecutingAssembly().FullName by executing it in calling project.
A cleaner solution would be:
var d = ClassSameAssembly.GetValues().ToDynamic();
Which is now an ExpandoObject.
Remember to reference:
Microsoft.CSharp.dll
ToExpando extension method (mentioned in Jon's answer) for the brave ones
public static class ExtensionMethods
{
public static ExpandoObject ToExpando(this object obj)
{
IDictionary<string, object> expando = new ExpandoObject();
foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(obj))
{
var value = propertyDescriptor.GetValue(obj);
expando.Add(propertyDescriptor.Name, value == null || new[]
{
typeof (Enum),
typeof (String),
typeof (Char),
typeof (Guid),
typeof (Boolean),
typeof (Byte),
typeof (Int16),
typeof (Int32),
typeof (Int64),
typeof (Single),
typeof (Double),
typeof (Decimal),
typeof (SByte),
typeof (UInt16),
typeof (UInt32),
typeof (UInt64),
typeof (DateTime),
typeof (DateTimeOffset),
typeof (TimeSpan),
}.Any(oo => oo.IsInstanceOfType(value))
? value
: value.ToExpando());
}
return (ExpandoObject)expando;
}
}
If you're already using Newtonsoft.Json in your project (or you're willing to add it for this purpose), you could implement that horrible extension method Jon Skeet is referring to in his answer like this:
public static class ObjectExtensions
{
public static ExpandoObject ToExpando(this object obj)
=> JsonConvert.DeserializeObject<ExpandoObject>(JsonConvert.SerializeObject(obj));
}

SQL Like keyword in Dynamic Linq

I want to use SQL's Like keyword in dynamic LINQ.
The query that I want to make is like this
select * from table_a where column_a like '%search%'
Where the column_a can be dynamically changed to other column etc
In this dynamic LINQ
var result = db.table_a.Where( a=> (a.column_a.Contains("search")) );
But the column can't be dynamically changed , only the search key can
How do we create a dynamic LINQ like
var result = db.table_a.Where("column_a == \"search\"");
That we can change the column and the search key dynamically
This should work for you:
.Where("AColumnName.Contains(#0)", "Criteria")
Create an ExtensionMethods class with this function
public static IQueryable<T> Like<T>(this IQueryable<T> source, string propertyName, string keyword)
{
var type = typeof(T);
var property = type.GetProperty(propertyName);
string number = "Int";
if (property.PropertyType.Name.StartsWith(number))
return source;
var parameter = Expression.Parameter(type, "p");
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
var constant = Expression.Constant("%" + keyword + "%");
MethodCallExpression methodExp = Expression.Call(null, typeof(SqlMethods).GetMethod("Like", new Type[] { typeof(string), typeof(string) }), propertyAccess, constant);
Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(methodExp, parameter);
return source.Where(lambda);
}
And then call it like this:
var result = db.table_a.Like("column_a", "%search%");
http://weblogs.asp.net/rajbk/archive/2007/09/18/dynamic-string-based-queries-in-linq.aspx
Addition:
Use an expression tree
How do I create an expression tree to represent 'String.Contains("term")' in C#?
That is what the dynamic linq library does internally.
I do not believe there is a direct translation to SQL for the LIKE keyword in LINQ. You could build one if you used expression trees, but I haven't gotten that good yet.
What I do is something like this:
using System.Data.Linq.SqlClient;
if (!string.IsNullOrEmpty(data.MailerName))
search = search.Where(a => SqlMethods.Like(a.Mailer.Name, string.Format("%{0}%", data.MailerName)));
where search is the query I'm building and data is the object containing the properties that hold the search criteria. I build the query dynamically by listing all of the possible search criteria in this way, which adds the appropriate Where methods to search.
Maybe a bit late but Another approach is add Extention method that use Contains to simulate Like keyword as :
public static class DbHelpers
{
public static IQueryable<T> Like<T>(this IQueryable<T> source, string propertyName, string propertyValue)
{
var prop = typeof(T).GetProperty(propertyName);
if (prop == null || prop.PropertyType.Name.StartsWith("Int"))
return source;
ParameterExpression parameter = Expression.Parameter(typeof(T), "row");
Expression property = Expression.Property(parameter, propertyName);
Expression value = Expression.Constant(propertyValue);
var containsmethod = value.Type.GetMethod("Contains", new[] { typeof(string) });
var call = Expression.Call(property, containsmethod, value);
var lambda = Expression.Lambda<Func<T, bool>>(call, parameter);
return source.Where(lambda);
}
}
And use of it:
var foo = entity.AsQueryable().Like("Name", "bla bla");
If send PropertyName with type of int, the method return original entity that you passed before to it.