views:

228

answers:

3

I have an Entity Framework 4.0 Entity Object called Revision w/ Nullable DateEffectiveFrom and DateEffectiveTo dates. I was wondering if there was a short-hand way of querying an object's RevisionHistory based on a particular QueryDate date instead of having to use the following query structure:

var results = EntityObject.Revisions.Where(x =>
    (x.DateEffectiveFrom == null && x.DateEffectiveTo == null) ||
    (x.DateEffectiveFrom == null && x.DateEffectiveTo >= QueryDate) ||
    (x.DateEffectiveFrom <= QueryDate && x.DateEffectiveTo == null) ||
    (x.DateEffectiveFrom <= QueryDate && x.DateEffectiveTo >= QueryDate));

I've tried creating the following boolean function in the Revision class:

partial class Revision
{
    public bool IsEffectiveOn(DateTime date)
    {
        return (x.DateEffectiveFrom == null && x.DateEffectiveTo == null) ||
            (x.DateEffectiveFrom == null && x.DateEffectiveTo >= date) ||
            (x.DateEffectiveFrom <= date && x.DateEffectiveTo == null) ||
            (x.DateEffectiveFrom <= date && x.DateEffectiveTo >= date));
    }
    ...
}

And then updating the query to:

var results = EntityObject.Revisions.Where(x => x.IsEffectiveOn(QueryDate));

but this obviously doesn't translate to SQL. Any ideas would be much appreciated.

+1  A: 

You can try Predicate Builder, and see if that translates to the appropriate SQL.

Robert Harvey
Thanks Robert - This seemed to do the trick for any IQuerable<Revision> queries (ie DataContext.Revisions). Any ideas for IEnumerable<Revision> scenarios. PS - I appreciate the detailed explanation of the use of predicates in the article as well.
Josh
For IEnumerable scenarios, you can see if [Dynamic Linq](http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx) works. Note that Dynamic Linq is not strongly-typed...you have to compose your predicates as strings.
Robert Harvey
A: 

The way you craft this query depends partly on what NULL means for EffectiveFrom and EffectiveTo.

If EffectiveFrom is NULL, should that mean that it is effective for all dates before EffectiveTo, and the reverse for NULL EffectiveTo? If that is the case, you can use DateTime.MinValue as a replacement for NULL EffectiveFrom values, and DateTime.MaxValue for EffectiveTo. At that point you can simply use BETWEEN-style queries:

Where(x => x.DateEffectiveFrom > QueryDate < x.DateEffectiveTo);
Dave Swersky
I appreciate the response Dave, but I'm trying to avoid this situation if I can.
Josh
+2  A: 

You can make your function return an Expression, rather than a bool:

partial class Revision
{
    public static Expression<Func<Revision, bool>> IsEffectiveOn(DateTime date)
    {
        return x => (x.DateEffectiveFrom == null && x.DateEffectiveTo == null) ||
            (x.DateEffectiveFrom == null && x.DateEffectiveTo >= date) ||
            (x.DateEffectiveFrom <= date && x.DateEffectiveTo == null) ||
            (x.DateEffectiveFrom <= date && x.DateEffectiveTo >= date));
    }
}

Then you can use it:

var predicate = Revision.IsEffectiveOn(DateTime.Now);
var results = EntityObject.Revisions.Where(predicate);

...and that will translate to SQL.

Craig Stuntz
Thanks Craig - I gave the answer to Robert as the article he referenced pointed to the solution you gave above. I'd bump your response up too if I could because I appreciate the code.
Josh
@Josh: I bumped it for you.
Robert Harvey
@Robert: Thanks...the joys of being a newbie :P
Josh