Quotes escape in Where clause in LINQ to Entites - c#

I wonder how to escape quotes in LINQ to Entities.
This is my environment : Entity Framework 5 with Silverlight 5 and WCF RIA Services, MySQL 5.6 and MySQLConnector 6.5.6.
I've got the following query:
DomainContext.Load<Product>(DomainContext.GetProductQuery()
.Where<Product>(p => p.name.Contains(parameter))
.Take<Product>(30));
If the parameter variable contains a quote ' it raises a MySQL syntax error exception.
Whatever the method (StartWith, Contains) it always raises an exception.
This does the same using FilterDescriptor with a DomainDataSource.
Important note : It does not raise any exception with characters like % or double quote ". Also it does not raise any exception with a simple quote if the operator is equal strict like the following.
DomainDataSource.FilterDescriptors.Add(new FilterDescriptor("productName", FilterOperator.IsEqualTo, SelectedProductName));
or
DomainContext.Load<Product>(DomainContext.GetProductQuery()
.Where<Product>(p == parameter)
.Take<Product>(30));
I don't have any difficulties to insert data.
Any help will be much appreciated.
Thank you.
Update: I forgot to mention some things.
This is my method on service side.
public IQueryable<Product> GetProduct()
{
return this.ObjectContext.product;
}
How am I supposed to secure this against SQL injections ? Do I have to write dozens lines of code to manage filters ?
EDIT : Issue is solved in the last version of the MySQL provider for EF.

For a quick solution for your exact problem:
string cleanParameter = parameter.Replace("'", "\'")
OR
Take a look here for a more general solution that describes the C# equivalent of mysql_real_escape_string.
string cleanParameter = MySQLEscape(parameter)
MySQLEscape as described in the mentioned article:
private static string MySQLEscape(string str)
{
return Regex.Replace(str, #"[\x00'""\b\n\r\t\cZ\\%_]",
delegate(Match match)
{
string v = match.Value;
switch (v)
{
case "\x00": // ASCII NUL (0x00) character
return "\\0";
case "\b": // BACKSPACE character
return "\\b";
case "\n": // NEWLINE (linefeed) character
return "\\n";
case "\r": // CARRIAGE RETURN character
return "\\r";
case "\t": // TAB
return "\\t";
case "\u001A": // Ctrl-Z
return "\\Z";
default:
return "\\" + v;
}
});
}
Side note: your code sounds like it may be prone to SQL injection attacks. (I can't tell without more context). This article describes what sql injection attacks are and how to prevent them.

I've found a workaround for this issue.
First, I would like to thank tomlev from www.developpez.net for his solution as chamamo for his help too.
This is the direct link to the discussion in French
http://www.developpez.net/forums/d1349604/services-web/wcf-ria-services-injection-sql/
This is the source code of a wrapper to fix this issue.
class MySqlQueryableWrapper<T> : IQueryable<T>
{
private readonly IQueryable<T> _queryable;
private readonly IQueryProvider _provider;
public MySqlQueryableWrapper(IQueryable<T> queryable)
{
_queryable = queryable;
_provider = new MySqlQueryProviderWrapper(queryable.Provider);
}
public Type ElementType
{
get { return _queryable.ElementType; }
}
public Expression Expression
{
get { return _queryable.Expression; }
}
public IQueryProvider Provider
{
get { return _provider; }
}
public IEnumerator<T> GetEnumerator()
{
return _queryable.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
class MySqlQueryProviderWrapper : IQueryProvider
{
private readonly MySqlExpressionFixer _visitor = new MySqlExpressionFixer();
private readonly IQueryProvider _provider;
public MySqlQueryProviderWrapper(IQueryProvider provider)
{
_provider = provider;
}
public IQueryable CreateQuery(Expression expression)
{
return _provider.CreateQuery(_visitor.Visit(expression));
}
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
return _provider.CreateQuery<TElement>(_visitor.Visit(expression));
}
public object Execute(Expression expression)
{
return _provider.Execute(_visitor.Visit(expression));
}
public TResult Execute<TResult>(Expression expression)
{
return _provider.Execute<TResult>(_visitor.Visit(expression));
}
}
class MySqlExpressionFixer : ExpressionVisitor
{
protected override Expression VisitMethodCall(MethodCallExpression node)
{
if ((node.Method.Name == "Contains" || node.Method.Name == "StartsWith") &&
node.Method.DeclaringType == typeof(string) &&
node.Arguments.Count == 1)
{
var c = node.Arguments[0] as ConstantExpression;
if (c != null)
{
string s = c.Value as string;
if (s != null)
{
s = s.Replace("'", "''");
node = Expression.Call(node.Object, node.Method, Expression.Constant(s));
}
}
}
return base.VisitMethodCall(node);
}
}
Here is an example.
public IQueryable<Product> GetProduct()
{
return new MySqlQueryableWrapper<Product>(this.ObjectContext.product);
}

Related

An expression tree lambda may not contain a null propagating operator

The line price = co?.price ?? 0, in the following code gives me the above error, but if I remove ? from co.? it works fine.
I was trying to follow this MSDN example where they are using ? on line select new { person.FirstName, PetName = subpet?.Name ?? String.Empty }; So, it seems I need to understand when to use ? with ?? and when not to.
Error:
an expression tree lambda may not contain a null propagating operator
public class CustomerOrdersModelView
{
public string CustomerID { get; set; }
public int FY { get; set; }
public float? price { get; set; }
....
....
}
public async Task<IActionResult> ProductAnnualReport(string rpt)
{
var qry = from c in _context.Customers
join ord in _context.Orders
on c.CustomerID equals ord.CustomerID into co
from m in co.DefaultIfEmpty()
select new CustomerOrdersModelView
{
CustomerID = c.CustomerID,
FY = c.FY,
price = co?.price ?? 0,
....
....
};
....
....
}
The example you were quoting from uses LINQ to Objects, where the implicit lambda expressions in the query are converted into delegates... whereas you're using EF or similar, with IQueryable<T> queryies, where the lambda expressions are converted into expression trees. Expression trees don't support the null conditional operator (or tuples).
Just do it the old way:
price = co == null ? 0 : (co.price ?? 0)
(I believe the null-coalescing operator is fine in an expression tree.)
The code you link to uses List<T>. List<T> implements IEnumerable<T> but not IQueryable<T>. In that case, the projection is executed in memory and ?. works.
You're using some IQueryable<T>, which works very differently. For IQueryable<T>, a representation of the projection is created, and your LINQ provider decides what to do with it at runtime. For backwards compatibility reasons, ?. cannot be used here.
Depending on your LINQ provider, you may be able to use plain . and still not get any NullReferenceException.
Jon Skeet's answer was right, in my case I was using DateTime for my Entity class.
When I tried to use like
(a.DateProperty == null ? default : a.DateProperty.Date)
I had the error
Property 'System.DateTime Date' is not defined for type 'System.Nullable`1[System.DateTime]' (Parameter 'property')
So I needed to change DateTime? for my entity class and
(a.DateProperty == null ? default : a.DateProperty.Value.Date)
While expression tree does not support the C# 6.0 null propagating, what we can do is create a visitor that modify expression tree for safe null propagation, just like the operator does!
Here is mine:
public class NullPropagationVisitor : ExpressionVisitor
{
private readonly bool _recursive;
public NullPropagationVisitor(bool recursive)
{
_recursive = recursive;
}
protected override Expression VisitUnary(UnaryExpression propertyAccess)
{
if (propertyAccess.Operand is MemberExpression mem)
return VisitMember(mem);
if (propertyAccess.Operand is MethodCallExpression met)
return VisitMethodCall(met);
if (propertyAccess.Operand is ConditionalExpression cond)
return Expression.Condition(
test: cond.Test,
ifTrue: MakeNullable(Visit(cond.IfTrue)),
ifFalse: MakeNullable(Visit(cond.IfFalse)));
return base.VisitUnary(propertyAccess);
}
protected override Expression VisitMember(MemberExpression propertyAccess)
{
return Common(propertyAccess.Expression, propertyAccess);
}
protected override Expression VisitMethodCall(MethodCallExpression propertyAccess)
{
if (propertyAccess.Object == null)
return base.VisitMethodCall(propertyAccess);
return Common(propertyAccess.Object, propertyAccess);
}
private BlockExpression Common(Expression instance, Expression propertyAccess)
{
var safe = _recursive ? base.Visit(instance) : instance;
var caller = Expression.Variable(safe.Type, "caller");
var assign = Expression.Assign(caller, safe);
var acess = MakeNullable(new ExpressionReplacer(instance,
IsNullableStruct(instance) ? caller : RemoveNullable(caller)).Visit(propertyAccess));
var ternary = Expression.Condition(
test: Expression.Equal(caller, Expression.Constant(null)),
ifTrue: Expression.Constant(null, acess.Type),
ifFalse: acess);
return Expression.Block(
type: acess.Type,
variables: new[]
{
caller,
},
expressions: new Expression[]
{
assign,
ternary,
});
}
private static Expression MakeNullable(Expression ex)
{
if (IsNullable(ex))
return ex;
return Expression.Convert(ex, typeof(Nullable<>).MakeGenericType(ex.Type));
}
private static bool IsNullable(Expression ex)
{
return !ex.Type.IsValueType || (Nullable.GetUnderlyingType(ex.Type) != null);
}
private static bool IsNullableStruct(Expression ex)
{
return ex.Type.IsValueType && (Nullable.GetUnderlyingType(ex.Type) != null);
}
private static Expression RemoveNullable(Expression ex)
{
if (IsNullableStruct(ex))
return Expression.Convert(ex, ex.Type.GenericTypeArguments[0]);
return ex;
}
private class ExpressionReplacer : ExpressionVisitor
{
private readonly Expression _oldEx;
private readonly Expression _newEx;
internal ExpressionReplacer(Expression oldEx, Expression newEx)
{
_oldEx = oldEx;
_newEx = newEx;
}
public override Expression Visit(Expression node)
{
if (node == _oldEx)
return _newEx;
return base.Visit(node);
}
}
}
It passes on the following tests:
private static string Foo(string s) => s;
static void Main(string[] _)
{
var visitor = new NullPropagationVisitor(recursive: true);
Test1();
Test2();
Test3();
void Test1()
{
Expression<Func<string, char?>> f = s => s == "foo" ? 'X' : Foo(s).Length.ToString()[0];
var fBody = (Expression<Func<string, char?>>)visitor.Visit(f);
var fFunc = fBody.Compile();
Debug.Assert(fFunc(null) == null);
Debug.Assert(fFunc("bar") == '3');
Debug.Assert(fFunc("foo") == 'X');
}
void Test2()
{
Expression<Func<string, int>> y = s => s.Length;
var yBody = visitor.Visit(y.Body);
var yFunc = Expression.Lambda<Func<string, int?>>(
body: yBody,
parameters: y.Parameters)
.Compile();
Debug.Assert(yFunc(null) == null);
Debug.Assert(yFunc("bar") == 3);
}
void Test3()
{
Expression<Func<char?, string>> y = s => s.Value.ToString()[0].ToString();
var yBody = visitor.Visit(y.Body);
var yFunc = Expression.Lambda<Func<char?, string>>(
body: yBody,
parameters: y.Parameters)
.Compile();
Debug.Assert(yFunc(null) == null);
Debug.Assert(yFunc('A') == "A");
}
}

Specifying deferred action before IQueryable has been evaluated

I would like to perform some post-processing on an entity that is returned from an IQueryable, but I would like to specify that post-processing before evaluating the query. So for example:
IQueryable<Client> GetClients()
{
return _context.Set<Client>()
.PostProcess(c => c.MobileNumber = c.MobileNumber.Replace(" ", ""));
}
Client GetClient(int id)
{
return GetClients()
.FirstOrDefault(c => c.Id == id);
}
In the above example I would want every Client returned from the above two methods to have all spaces removed from their mobile number. Is this possible?
Edit: This is a bad idea
It works in the simple case stated in the OP, but any further IQueryable extensions (such as a .Where() clause) will discard the post-processing behaviour. I'm not sure it's technically possible to do what I want to do, and now I come to think of it I'm not even sure what the semantics would be beyond the simple case. Still, the simple case works and is quite handy to keep things fluent...
Original:
I thought I would share my approach for this in case someone finds it useful (or has a comment on why it's a bad idea). The solution uses two decorators to defer the post-processing action until the query is executed, and an extension method to set them up:
public static class QueryableExtensions
{
public static IQueryable<T> PostProcess<T>(this IQueryable<T> source, Action<T> postProcessor) where T : class
{
return new QueryableWrapper<T>(source, postProcessor);
}
// wraps IQueryProvider.Execute methods with post-processing action
class QueryProviderWrapper<T> : IQueryProvider where T : class
{
private readonly IQueryProvider _wrapped;
private readonly Action<T> _postProcessor;
public QueryProviderWrapper(IQueryProvider wrapped, Action<T> postProcessor)
{
_wrapped = wrapped;
_postProcessor = postProcessor;
}
public IQueryable CreateQuery(Expression expression)
{
return _wrapped.CreateQuery(expression);
}
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
return _wrapped.CreateQuery<TElement>(expression);
}
public object Execute(Expression expression)
{
var result = _wrapped.Execute(expression);
var asT = result as T;
if (asT != null)
_postProcessor(asT);
return result;
}
public TResult Execute<TResult>(Expression expression)
{
var result = _wrapped.Execute<TResult>(expression);
var asT = result as T;
if (asT != null)
_postProcessor(asT);
return result;
}
}
// wraps IQueryable.GetEnumerator() with post-processing action
class QueryableWrapper<T> : IQueryable<T> where T : class
{
private readonly IQueryable<T> _wrapped;
private readonly Action<T> _postProcessor;
private readonly IQueryProvider _provider;
public QueryableWrapper(IQueryable<T> wrapped, Action<T> postProcessor)
{
_wrapped = wrapped;
_postProcessor = postProcessor;
_provider = new QueryProviderWrapper<T>(_wrapped.Provider, postProcessor);
}
public Expression Expression
{
get { return _wrapped.Expression; }
}
public Type ElementType
{
get { return _wrapped.ElementType; }
}
public IQueryProvider Provider
{
get { return _provider; }
}
public IEnumerator<T> GetEnumerator()
{
return _wrapped
.AsEnumerable()
.Do(_postProcessor)
.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
The GetEnumerator() decorator uses the .Do() extension method from Interactive Extensions which is like a cross between Select and ForEach: it is lazily invoked, but takes an Action<T> and returns T

C# Converting Lambda Expression Function to Descriptive String

I have quite an unnecessary dilemma. I'm lazily looking for a function that would convert a lamda expression into a string. It bothers me that I'm typing in this cache key every time but I don't really want to take the time to create it.
I want to use it for a cache function I created:
Where if I wanted to get a name for a person without calling the function every time.
public static string GetPersonName(int id)
{
return Repository.PersonProvider.Cached(x => x.GetById(id)).Name;
}
The GetExpressionDescription would return "PersonProvider.GetById(int 10)"
I figure this is possible but I wonder if anyone has already built this or has seen it somewhere.
public static R Cached<T, R>(this T obj, Expression<Func<T, R>> function, double hours = 24)
{
var expressionDescription = GetExpressionDescription(function);
return Cached(function, expressionDescription, hours);
}
public static R Cached<T, R>(this T obj, Expression<Func<T, R>> function, string cacheName, double hours = 24)
{
var context = HttpContext.Current;
if (context == null)
return function.Compile().Invoke(obj);
R results = default(R);
try { results = (R)context.Cache[cacheName]; }
catch { }
if (results == null)
{
results = function.Compile().Invoke(obj);
if (results != null)
{
context.Cache.Add(cacheName, results, null, DateTime.Now.AddHours(hours),
Cache.NoSlidingExpiration,
CacheItemPriority.Default, null);
}
}
return results;
}
You can simply get a string representation of an Expression<> with .ToString():
using System;
using System.Linq.Expressions;
public class Program
{
public static void Main()
{
Test(s => s.StartsWith("A"));
}
static void Test(Expression<Func<string,bool>> expr)
{
Console.WriteLine(expr.ToString());
Console.ReadKey();
}
}
Prints:
s => s.StartsWith("A")
See: https://dotnetfiddle.net/CJwAE5
But of course it will not yield you the caller and the values of variables, just the expression itself.
Maybe you should try DynamicExpresso. I used that library to develop a lightweight business-rules engine.
https://github.com/davideicardi/DynamicExpresso

EntityFramework 4 OrderBy overwrites previous OrderBy calls

I often want to provide orderings for IQueryables that should act like secondary orderings if another is specified later. For example, the following:
Repository.All.OrderBy(o => o.Name).OrderBy(o => o.SerialNumber) [A]
Should be equivalent to:
Repository.All.OrderBy(o => o.SerialNumber).ThenBy(o => o.Name)
This worked correctly using LINQ to SQL. However, in EntityFramework 4, the Order-By clause in the generated SQL looks like this:
ORDER BY [Project1].[SerialNumber] ASC
It completely ignores the first OrderBy statement, which actually breaks OrderBy being a stable sort. ThenBy is not an option for me, because the orderings are not always defined in the same place (for example, in statement [A] above, the OrderBy(o => o.Name) could be defined in the Repository. Extensions to IQueryable<TModel> are not a good solution either, because it doesn't allow different Repositories to sort differently, and the consuming code should not have to call some .SortDefault() code since that's not its concern.
Is there any good way to force Linq to Entities to respect multiple OrderBy statements?
Thanks
I don't agree that a subsequent OrderBy should be equivalent to a ThenBy. If that were so, there would be no need for ThenBy and you could never override an existing sort.
I can't say I like it, but off the top of my head this would seem an option for downstream sorting:
IQueryable<Item> items = Repository.GetAllWhichMightBeOrderedAlready();
return items is IOrderedEnumerable<Item>
? ((IOrderedQueryable<Item>)items).ThenBy(x => x.SomeProperty)
: items.OrderBy(x => x.SomeProperty);
Substitute IOrderedEnumerable<T> as appropriate.
Ok, it's not the most elegant solution, but I was able to overcome this in a way that seems to work fine, although I suspect all the funky reflection may make it too slow. I created my own custom IQueryable class and associated query provider that take an ExpressionVisitor and call .Visit() on that visitor on GetEnumerator and Execute calls. My base repository class returns a new MappedExpressionQuery and passes it the query returned from DbContext.Set() along with an ExpressionVisitor that produces the desired ordering. The custom queryable and provider classes:
public class MappedExpressionQuery<T> : IOrderedQueryable<T>
{
private IQueryable<T> baseQuery;
private MappedExpressionQueryProvider<T> provider;
public MappedExpressionQuery(IQueryable<T> query, ExpressionVisitor expressionMap)
{
baseQuery = query;
provider = new MappedExpressionQueryProvider<T>(query.Provider, expressionMap);
}
#region IOrderedQueryable<T> Members
public IEnumerator<T> GetEnumerator()
{
return baseQuery.Provider.CreateQuery<T>(provider.ExpressionMap.Visit(baseQuery.Expression)).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return baseQuery.Provider.CreateQuery(provider.ExpressionMap.Visit(baseQuery.Expression)).GetEnumerator();
}
public Type ElementType
{
get { return baseQuery.ElementType; }
}
public Expression Expression
{
get { return baseQuery.Expression; }
}
public IQueryProvider Provider
{
get { return provider; }
}
#endregion
}
public class MappedExpressionQueryProvider<T> : IQueryProvider
{
public ExpressionVisitor ExpressionMap { get; private set; }
private IQueryProvider baseProvider;
public MappedExpressionQueryProvider(IQueryProvider baseProvider, ExpressionVisitor expressionMap)
{
this.ExpressionMap = expressionMap;
this.baseProvider = baseProvider;
}
#region IQueryProvider Members
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
return new MappedExpressionQuery<TElement>(baseProvider.CreateQuery<TElement>(expression), ExpressionMap);
}
public IQueryable CreateQuery(Expression expression)
{
throw new NotImplementedException();
}
public TResult Execute<TResult>(Expression expression)
{
return baseProvider.Execute<TResult>(ExpressionMap.Visit(expression));
}
public object Execute(Expression expression)
{
return baseProvider.Execute(ExpressionMap.Visit(expression));
}
#endregion
}
When my custom ExpressionVisitor class finds an OrderBy or ThenBy statement, it travels down the expression tree recording the proper orders each sort should be in until it finds a statement that is not an Order statement and is not commutative with an Order statement. Then it builds up all the statements again at the end of the expression. So OrderBy(A).ThenBy(B).OrderBy(C).OrderBy(D).ThenBy(E) is returned with the following additional expressions attached to the end: .OrderBy(D).ThenBy(E).ThenBy(C).ThenBy(A).ThenBy(B). Yes, it is redundant, but EntityFramework ignores the expressions further down the chain anyway, and I only use this QueryProvider with queryables that come from the DbContext. The code for this expression visitor (I also threw in a fix for the fact that .ToString() doesn't translate to SQL even when used on constants, so DbContext.Set<T>().Where(o => o.Name == SomeConstant.ToString()) works now):
public abstract class QueryModifier : ExpressionVisitor
{
private bool OrganizedOrdering { get; set; }
protected override Expression VisitMethodCall(MethodCallExpression node)
{
if (node.Method.Name == "ToString" && node.Method.DeclaringType == typeof(object))
{
try
{
//If the object calling ToString is parameterless, invoke the method and convert it into a constant.
return Expression.Constant(Expression.Lambda(node).Compile().DynamicInvoke());
}
catch (InvalidOperationException)
{
throw new InvalidOperationException("ToString() can only be translated into SQL when used on parameterless expressions.");
}
}
else if (IsOrderStatement(node.Method))
{
if (!OrganizedOrdering)
{
OrganizedOrdering = true;
return RearrangeOrderStatements(node);
}
else
return base.VisitMethodCall(node);
}
else if (OrganizedOrdering && !IsOrderCommutative(node.Method))
{
OrganizedOrdering = false;
return base.VisitMethodCall(node);
}
else
{
return base.VisitMethodCall(node);
}
}
private Expression RearrangeOrderStatements(MethodCallExpression node)
{
//List to store (OrderBy expression, position) tuples
List<Tuple<MethodCallExpression, double>> orderByExpressions = new List<Tuple<MethodCallExpression, double>>();
double low = 0;
double high = 1;
MethodCallExpression startNode = node;
Expression lastNode = node.Arguments[0];
//Travel down the chain and store all OrderBy and ThenBy statements found with their relative positions
while (node != null && node.Method.DeclaringType == typeof(System.Linq.Queryable))
{
if (node.Arguments.Count == 0)
break;
if (node.Method.Name.StartsWith("OrderBy"))
{
orderByExpressions.Add(new Tuple<MethodCallExpression, double>(node, low));
low = low + 1;
high = low + 1;
}
else if (node.Method.Name.StartsWith("ThenBy"))
{
double pos = (high - low) * 0.9 + low;
orderByExpressions.Add(new Tuple<MethodCallExpression, double>(node, pos));
high = pos;
}
else if (!IsOrderCommutative(node.Method))
{
break;
}
lastNode = node.Arguments[0];
node = lastNode as MethodCallExpression;
}
lastNode = startNode;
var methods = typeof(Queryable).GetMethods().Where(o => IsOrderStatement(o));
Type queryType = startNode.Arguments[0].Type.GetGenericArguments()[0];
bool firstStatement = true;
foreach (var tuple in orderByExpressions.OrderBy(o => o.Item2))
{
string methodName;
if (firstStatement)
{
methodName = "OrderBy";
firstStatement = false;
}
else
methodName = "ThenBy";
if (tuple.Item1.Method.Name.EndsWith("Descending"))
methodName = methodName + "Descending";
Type orderByTValueType = tuple.Item1.Arguments[1].Type.GetGenericArguments()[0].GetGenericArguments()[1];
if (tuple.Item1.Arguments.Count == 3)
{
var method = methods.Single(o => o.Name == methodName && o.GetParameters().Length == 3)
.MakeGenericMethod(queryType, orderByTValueType);
lastNode = Expression.Call(method, lastNode, tuple.Item1.Arguments[1], tuple.Item1.Arguments[2]);
}
else
{
var method = methods.Single(o => o.Name == methodName && o.GetParameters().Length == 2)
.MakeGenericMethod(queryType, orderByTValueType);
lastNode = Expression.Call(method, lastNode, tuple.Item1.Arguments[1]);
}
}
return Visit(lastNode);
}
/// <summary>
/// Returns true if the given method call expression is commutative with OrderBy statements.
/// </summary>
/// <param name="expression"></param>
/// <returns></returns>
private bool IsOrderCommutative(MethodInfo method)
{
return new string[] { "Where", "Distinct", "AsQueryable" }.Contains(method.Name)
&& method.DeclaringType == typeof(System.Linq.Queryable);
}
private bool IsOrderStatement(MethodInfo method)
{
return (method.Name.StartsWith("OrderBy") || method.Name.StartsWith("ThenBy"))
&& method.DeclaringType == typeof(System.Linq.Queryable);
}
}
So you can't use ThenBy because the initial OrderBy might be skipped? How about doing an initial dummy OrderBy, then all the others are ThenBy.
// Basically, everything gets the same orderby ranking
// I don't know offhand if you can use a constant here, but if you have an id,
// you should be able to this.
var list = context.MyTable.OrderBy(mt => mt.id - mt.id);
if (order by field1)
list = list.ThenBy(mt => mt.field1);
if (order by field2)
list = list.ThenBy(mt => mt.field2);
etc...
EDIT: Nevermind. This doesn't work. Can't use ThenBy on a seperate line by itself, as I was thinking.

How to wrap Entity Framework to intercept the LINQ expression just before execution?

I want to rewrite certain parts of the LINQ expression just before execution. And I'm having problems injecting my rewriter in the correct place (at all actually).
Looking at the Entity Framework source (in reflector) it in the end comes down to the IQueryProvider.Execute which in EF is coupled to the expression by the ObjectContext offering the internal IQueryProvider Provider { get; } property.
So I created a a wrapper class (implementing IQueryProvider) to do the Expression rewriting when the Execute gets called and then pass it to the original Provider.
Problem is, the field behind Provider is private ObjectQueryProvider _queryProvider;. This ObjectQueryProvider is an internal sealed class, meaning it's not possible to create a subclass offering the added rewriting.
So this approach got me to a dead end due to the very tightly coupled ObjectContext.
How to solve this problem? Am I looking in the wrong direction? Is there perhaps a way to inject myself around this ObjectQueryProvider?
Update: While the provided solutions all work when you're "wrapping" the ObjectContext using the Repository pattern, a solution which would allow for direct usage of the generated subclass from ObjectContext would be preferable. Hereby remaining compatible with the Dynamic Data scaffolding.
Based on the answer by Arthur I've create a working wrapper.
The snippets provided provide a way to wrap each LINQ query with your own QueryProvider and IQueryable root. This would mean that you've got to have control over the initial query starting (as you'll have most of the time using any sort of pattern).
The problem with this method is that it's not transparent, a more ideal situation would be to inject something in the entities container at the constructor level.
I've created a compilable the implementation, got it to work with entity framework, and added support for the ObjectQuery.Include method. The expression visitor class can be copied from MSDN.
public class QueryTranslator<T> : IOrderedQueryable<T>
{
private Expression expression = null;
private QueryTranslatorProvider<T> provider = null;
public QueryTranslator(IQueryable source)
{
expression = Expression.Constant(this);
provider = new QueryTranslatorProvider<T>(source);
}
public QueryTranslator(IQueryable source, Expression e)
{
if (e == null) throw new ArgumentNullException("e");
expression = e;
provider = new QueryTranslatorProvider<T>(source);
}
public IEnumerator<T> GetEnumerator()
{
return ((IEnumerable<T>)provider.ExecuteEnumerable(this.expression)).GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return provider.ExecuteEnumerable(this.expression).GetEnumerator();
}
public QueryTranslator<T> Include(String path)
{
ObjectQuery<T> possibleObjectQuery = provider.source as ObjectQuery<T>;
if (possibleObjectQuery != null)
{
return new QueryTranslator<T>(possibleObjectQuery.Include(path));
}
else
{
throw new InvalidOperationException("The Include should only happen at the beginning of a LINQ expression");
}
}
public Type ElementType
{
get { return typeof(T); }
}
public Expression Expression
{
get { return expression; }
}
public IQueryProvider Provider
{
get { return provider; }
}
}
public class QueryTranslatorProvider<T> : ExpressionVisitor, IQueryProvider
{
internal IQueryable source;
public QueryTranslatorProvider(IQueryable source)
{
if (source == null) throw new ArgumentNullException("source");
this.source = source;
}
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
if (expression == null) throw new ArgumentNullException("expression");
return new QueryTranslator<TElement>(source, expression) as IQueryable<TElement>;
}
public IQueryable CreateQuery(Expression expression)
{
if (expression == null) throw new ArgumentNullException("expression");
Type elementType = expression.Type.GetGenericArguments().First();
IQueryable result = (IQueryable)Activator.CreateInstance(typeof(QueryTranslator<>).MakeGenericType(elementType),
new object[] { source, expression });
return result;
}
public TResult Execute<TResult>(Expression expression)
{
if (expression == null) throw new ArgumentNullException("expression");
object result = (this as IQueryProvider).Execute(expression);
return (TResult)result;
}
public object Execute(Expression expression)
{
if (expression == null) throw new ArgumentNullException("expression");
Expression translated = this.Visit(expression);
return source.Provider.Execute(translated);
}
internal IEnumerable ExecuteEnumerable(Expression expression)
{
if (expression == null) throw new ArgumentNullException("expression");
Expression translated = this.Visit(expression);
return source.Provider.CreateQuery(translated);
}
#region Visitors
protected override Expression VisitConstant(ConstantExpression c)
{
// fix up the Expression tree to work with EF again
if (c.Type == typeof(QueryTranslator<T>))
{
return source.Expression;
}
else
{
return base.VisitConstant(c);
}
}
#endregion
}
Example usage in your repository:
public IQueryable<User> List()
{
return new QueryTranslator<User>(entities.Users).Include("Department");
}
I have exactly the sourcecode you'll need - but no idea how to attach a File.
Here are some snippets (snippets! I had to adapt this code, so it may not compile):
IQueryable:
public class QueryTranslator<T> : IOrderedQueryable<T>
{
private Expression _expression = null;
private QueryTranslatorProvider<T> _provider = null;
public QueryTranslator(IQueryable source)
{
_expression = Expression.Constant(this);
_provider = new QueryTranslatorProvider<T>(source);
}
public QueryTranslator(IQueryable source, Expression e)
{
if (e == null) throw new ArgumentNullException("e");
_expression = e;
_provider = new QueryTranslatorProvider<T>(source);
}
public IEnumerator<T> GetEnumerator()
{
return ((IEnumerable<T>)_provider.ExecuteEnumerable(this._expression)).GetEnumerator();
}
IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _provider.ExecuteEnumerable(this._expression).GetEnumerator();
}
public Type ElementType
{
get { return typeof(T); }
}
public Expression Expression
{
get { return _expression; }
}
public IQueryProvider Provider
{
get { return _provider; }
}
}
IQueryProvider:
public class QueryTranslatorProvider<T> : ExpressionTreeTranslator, IQueryProvider
{
IQueryable _source;
public QueryTranslatorProvider(IQueryable source)
{
if (source == null) throw new ArgumentNullException("source");
_source = source;
}
#region IQueryProvider Members
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
if (expression == null) throw new ArgumentNullException("expression");
return new QueryTranslator<TElement>(_source, expression) as IQueryable<TElement>;
}
public IQueryable CreateQuery(Expression expression)
{
if (expression == null) throw new ArgumentNullException("expression");
Type elementType = expression.Type.FindElementTypes().First();
IQueryable result = (IQueryable)Activator.CreateInstance(typeof(QueryTranslator<>).MakeGenericType(elementType),
new object[] { _source, expression });
return result;
}
public TResult Execute<TResult>(Expression expression)
{
if (expression == null) throw new ArgumentNullException("expression");
object result = (this as IQueryProvider).Execute(expression);
return (TResult)result;
}
public object Execute(Expression expression)
{
if (expression == null) throw new ArgumentNullException("expression");
Expression translated = this.Visit(expression);
return _source.Provider.Execute(translated);
}
internal IEnumerable ExecuteEnumerable(Expression expression)
{
if (expression == null) throw new ArgumentNullException("expression");
Expression translated = this.Visit(expression);
return _source.Provider.CreateQuery(translated);
}
#endregion
#region Visits
protected override MethodCallExpression VisitMethodCall(MethodCallExpression m)
{
return m;
}
protected override Expression VisitUnary(UnaryExpression u)
{
return Expression.MakeUnary(u.NodeType, base.Visit(u.Operand), u.Type.ToImplementationType(), u.Method);
}
#endregion
}
Usage (warning: adapted code! May not compile):
private Dictionary<Type, object> _table = new Dictionary<Type, object>();
public override IQueryable<T> GetObjectQuery<T>()
{
if (!_table.ContainsKey(type))
{
_table[type] = new QueryTranslator<T>(
_ctx.CreateQuery<T>("[" + typeof(T).Name + "]"));
}
return (IQueryable<T>)_table[type];
}
Expression Visitors/Translator:
http://blogs.msdn.com/mattwar/archive/2007/07/31/linq-building-an-iqueryable-provider-part-ii.aspx
http://msdn.microsoft.com/en-us/library/bb882521.aspx
EDIT: Added FindElementTypes(). Hopefully all Methods are present now.
/// <summary>
/// Finds all implemented IEnumerables of the given Type
/// </summary>
public static IQueryable<Type> FindIEnumerables(this Type seqType)
{
if (seqType == null || seqType == typeof(object) || seqType == typeof(string))
return new Type[] { }.AsQueryable();
if (seqType.IsArray || seqType == typeof(IEnumerable))
return new Type[] { typeof(IEnumerable) }.AsQueryable();
if (seqType.IsGenericType && seqType.GetGenericArguments().Length == 1 && seqType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
{
return new Type[] { seqType, typeof(IEnumerable) }.AsQueryable();
}
var result = new List<Type>();
foreach (var iface in (seqType.GetInterfaces() ?? new Type[] { }))
{
result.AddRange(FindIEnumerables(iface));
}
return FindIEnumerables(seqType.BaseType).Union(result);
}
/// <summary>
/// Finds all element types provided by a specified sequence type.
/// "Element types" are T for IEnumerable<T> and object for IEnumerable.
/// </summary>
public static IQueryable<Type> FindElementTypes(this Type seqType)
{
return seqType.FindIEnumerables().Select(t => t.IsGenericType ? t.GetGenericArguments().Single() : typeof(object));
}
Just wanted to add to Arthur's example.
As Arthur warned there is a bug in his GetObjectQuery() method.
It creates the base Query using typeof(T).Name as the name of the EntitySet.
The EntitySet name is quite distinct from the type name.
If you are using EF 4 you should do this:
public override IQueryable<T> GetObjectQuery<T>()
{
if (!_table.ContainsKey(type))
{
_table[type] = new QueryTranslator<T>(
_ctx.CreateObjectSet<T>();
}
return (IQueryable<T>)_table[type];
}
Which works so long as you don't have Multiple Entity Sets per Type (MEST) which is very rare.
If you are using 3.5 you can use the code in my Tip 13 to get the EntitySet name and feed it in like this:
public override IQueryable<T> GetObjectQuery<T>()
{
if (!_table.ContainsKey(type))
{
_table[type] = new QueryTranslator<T>(
_ctx.CreateQuery<T>("[" + GetEntitySetName<T>() + "]"));
}
return (IQueryable<T>)_table[type];
}
Hope this helps
Alex
Entity Framework Tips

Categories