Reputation: 32428
I'm trying to add a computed column to my linq object created from an SQL table. I can't do this in the database.
public partial class History_SHIP
{
public Expression<Func<DateTime>> TransactionDateTime
{
get
{
return () => TransactionDate.AddMinutes(SqlMethods.DateDiffMinute(TransactionTime, new DateTime(1900, 1, 1)));
}
}
}
I'd like to be able to use it as part of a where clause like below:
where sh.TransactionDateTime >= startDate
startDate
is a DateTime
and sh
is my History_SHIP
object.
I'd also like to be able to easily use it in a select statement too (I'm happy to create another property that does a TranslationDateTime.Compile()()
).
The problem I have with the where clause is that the LHS in a Expression<Func<DateTime>>
and the RHS is a DateTime
, so it complains.
I have seen this link http://www.codeproject.com/Articles/32968/QueryMap-Custom-translation-of-LINQ-expressions but don't want additional dependencies for this one property (for now anyway).
Upvotes: 3
Views: 981
Reputation: 1062620
Yes, that isn't going to be happy, for various reasons;
this
, but in reality we need something in relation to a ParameterExpression
(aka sh
)The easiest thing to do is probably to add an extension method that lets you filter on this conveniently, for example by re-writing an Expression
:
var filtered = source.WhereTransactionDate(when => when > DateTime.Now);
with implementation:
static class Utils
{
static readonly Expression<Func<Foo, DateTime>> tranDateTime =
x => x.TransactionDate.AddMinutes(SqlMethods.DateDiffMinute(
x.TransactionTime, new DateTime(1900, 1, 1)));
public static IQueryable<Foo> WhereTransactionDate(
this IQueryable<Foo> source,
Expression<Func<DateTime, bool>> predicate)
{
var visited = SwapVisitor.Swap(predicate.Body,
predicate.Parameters.Single(), tranDateTime.Body);
var lambda = Expression.Lambda<Func<Foo, bool>>(
visited, tranDateTime.Parameters);
return source.Where(lambda);
}
class SwapVisitor : ExpressionVisitor
{
public static Expression Swap(Expression source,
Expression from, Expression to)
{
return new SwapVisitor(from, to).Visit(source);
}
private SwapVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
readonly Expression from, to;
public override Expression Visit(Expression node)
{
return node == from ? to : base.Visit(node);
}
}
}
What this does is merge two expression-trees, i.e.
x => x.TransactionDate.AddMinutes(SqlMethods.DateDiffMinute(
x.TransactionTime, new DateTime(1900, 1, 1)))
and:
when => when > DateTime.Now
replacing all when
with the body from the first expression (and using the parameter from the first expression) i.e. creating
x => x.TransactionDate.AddMinutes(SqlMethods.DateDiffMinute(
x.TransactionTime, new DateTime(1900, 1, 1))) > DateTime.Now;
Upvotes: 1
Reputation: 14672
How about...
where sh.TransactionDateTime.Compile().Invoke() >= startDate
Upvotes: 0