开发者

"Or" Together Expression<Func<EntityFramework Entity, bool>> in .NET 4, Silverlight RIA domain service

I have a small custom object defined as:

public class TimeSeriesDefinition
{  
    public int classID;
    public DateTime startTime;
    public DateTime endTime;
}

I'm passing a List classIDs, a List startTimes, and a List endTimes into an RIA Domain Service function. As a matter of organization, I was grouping these values into a List of TimeSeriesDefinitions and then trying to use a foreach loop to create an expression that would select with AND operators between the values in a class and OR operators between each class or implement a ".Any" query as suggested by the first answer I received below. The problem is that I can't use the TimeSer开发者_如何学PythoniesDefinition class in a DomainService function because it is not a primitive type or one of my entity types (maybe I should just make an entity with this type?), so I need another method of achieving the desired query results. My original idea for using expressions that I never got anywhere with is here:

        Expression<Func<EventLog, bool>> bounds;
        Boolean assignedBounds = false;
        foreach (TimeSeriesDefinition ts in reporters)
        {
            if (assignedBounds.Equals(false))
            { 
                bounds = c => c.reporterID == ts.classID && c.reportDateTime >= ts.startTime && c.reportDateTime <= ts.endTime; 
                assignedBounds = true;
            }
            else
            { 
                Expression<Func<EventLog, bool>> newBounds = c => c.reporterID == ts.classID && c.reportDateTime >= ts.startTime && c.reportDateTime <= ts.endTime;
                bounds = Expression.Or(Expression.Invoke(bounds), Expression.Invoke(newBounds);
                // bounds = Expression<Func<EventLog, bool>>.Or(bounds, newBounds);
            }
        }

        return this.ObjectContext.EventLog.Where(bounds);

My goal is for the resultset to have all records of a ts.classID between ts.startDate and ts.EndDate. From what I've found online, it seems that making sure the parameters are correctly assigned is tricky as well, but right now I'm still getting a

"Cannot implicitly convert type 'System.Linq.Expressions.BinaryExpression' to 'System.Linq.Expressions.Expression>'"

error at the line

 bounds = Expression.Or(Expression.Invoke(bounds), Expression.Invoke(newBounds);

Can anybody point me in the right direction? I suppose I could possibly build this whole thing into a query string somehow, but I'd rather not go there.

Thanks in advance for your insight!


If you Funcletize (localize) your references to TimeSeriesDefinition on the client side, you should be able to include them in your query (see Evaluator.PartialEval method in here http://msdn.microsoft.com/en-us/library/bb546158.aspx). You should be able to simply call it on your Expression object and have the references to TimeSeriesDefinitions lifted away to primitive constants:

Evaluator.PartialEval(lambdaExpression);

As for your compilation problem:

bounds = Expression.Or(Expression.Invoke(bounds), Expression.Invoke(newBounds);

The left hand side of that assignment is a generic LambdaExpression. The right hande side is a BinaryExpression. To do the assignment, you need to Lambda the Or and also provide a ParameterExpression for your InvocationExpressions:

var parameterExpression = Expression.Parameter(typeof(EventLog));
bounds = Expression.Lambda<Func<EventLog, bool>>(  
    Expression.Or(  
         Expression.Invoke(bounds, parameterExpression),  
         Expression.Invoke(newBounds, parameterExpression), 
    parameterExpression);

However...you will probably run into the wonderful fact that RIA doesn't support InvocationExpressions... (I haven't verified this but I know EF doesn't). You've got to Expand your InvocationExpressions to inline them (sort of like with the Funcletlizer mentioned above).

LINQKit ( http://www.albahari.com/nutshell/linqkit.aspx ) provides one out of the box. It also provides helper methods for combining criteria as you mention above. If you don't want the whole dependency on LINQKit, you can grab the source for the same thing here: http://www.java2s.com/Open-Source/CSharp/Content-Management-Systems-CMS/Kooboo/Microsoft/Data/Extensions/DataExtensions.cs.htm

Then just change your Where to:

return this.ObjectContext.EventLog.Where(InvocationExpander.Expand(bounds));


Instead of List<TimeSeriesDefinition> can you use List<Tuple<int, DateTime, DateTime>>. Your query would then be this...

return ObjectContext.EventLog.Where(c =>
           reporters.Any(r =>
               c.reporterID == r.Item1 &&
               c.reportDateTime >= r.Item2 &&
               c.reportDateTime <= r.Item3));
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜