You can create custom extension methods for Linq to entities?
Yes, but that’s a bit complex. I’ll explain the guidelines on how to do this.
Linq to Entities translates each extension method into a predicate according to the preview, that is, if I make a Where()
, the preview SQL Server will translate the extension to SQL with the best possible compatibility for SQL Server. The preview Mysql will do the same thing for Mysql, and so on.
Therefore, the correct way to intercede in the SQL generation process is to reimplementate the ExpressionVisitor
:
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
}
And then, implement your SameDate
within a IOrderedQueryable<T>
:
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> SameDate(DateTimeOffset? source, DateTime? date)
{
// Implemente aqui
}
public Type ElementType
{
get { return typeof(T); }
}
public Expression Expression
{
get { return expression; }
}
public IQueryProvider Provider
{
get { return provider; }
}
}
Within it, you can create your own extension methods by correctly intercepting calls to the preview of the database. The general idea is here (question and answers).
It would be better to [Dit] the question and post as you created it. Then we can see where you are going wrong.
– Maniero
Buddy, you’re applying a
All
at the base and then applies theWhere
? This is making you bring all the information from the base and then filtering in memory, do not recommend you do this.– Gabriel Katakura
@Gabrielkatakura All() from this repository returns a Queryable.
– Eduardo Moreira
@Eduardomoreira ah, all right then ;)
– Gabriel Katakura
Now I understand your problem better... I can think of two solutions, but I can’t do it now, I have no resources at the moment, at home if no one help you I edit my answer.
– Gabriel Katakura