patterncsharpMinor
A generic way to use LINQ to Entity with types and operations unknown until run time
Viewed 0 times
genericlinqoperationsrununtilwithunknownwaytimetypes
Problem
A question was asked here about reflection and LINQ to entity. I'm trying to modify the code that was presented to fit my needs.
Here's what I am trying to accomplish: I'm writing back-end support for a web site that will be able to run reports on data we have. I want to write this as generically as possible so that the UI has the latitude to query however it wants without having to change the back end.
Leaning heavily on the above-mentioned link, and also using LinqKit I've cobbled together something that appears to work, but it's kinda' ugly and I was hoping there was a way to slim it down a bit.
First, I want to be able to pass arbitrarily complex and/or statements to the search. This part I'm perfectly satisfied with, but I'm including it as a reference to the next part:
The most important part to notice here is
This list of conditions is a way for us to say that some key (first string) relates in a specified way (
public List GetFoosBy(QueryGroup qGroup)
{
var pred = parseQueryGroup(qGroup);
ret
Here's what I am trying to accomplish: I'm writing back-end support for a web site that will be able to run reports on data we have. I want to write this as generically as possible so that the UI has the latitude to query however it wants without having to change the back end.
Leaning heavily on the above-mentioned link, and also using LinqKit I've cobbled together something that appears to work, but it's kinda' ugly and I was hoping there was a way to slim it down a bit.
First, I want to be able to pass arbitrarily complex and/or statements to the search. This part I'm perfectly satisfied with, but I'm including it as a reference to the next part:
public class QueryGroup
{
public readonly List> conditions;
public List qGroups;
public Operators Operator { get; private set; }
public QueryGroup(Operators op)
{
Operator = op;
conditions = new List>();
}
}
public enum CompareTypes
{
Equals, GreaterThan, LessThan
}
public enum Operators
{
And, Or
};The most important part to notice here is
public readonly List> conditions;This list of conditions is a way for us to say that some key (first string) relates in a specified way (
CompareTypes like ==, `, etc.) to a given value (second string). So for an object Foo, if Foo had a member Bar and we wanted to compare the value of Foo.Bar, then the first string would be "Bar" (note that we will already know we are searching for properties inside of Foo). If we wanted to say that the value of "Bar" should be equal to, say, 5, then the CompareType would be CompareTypes.Equals and the last string would be "5".
OK, on to the ugly part...
Continuing on the Foo/Bar example from above, let's say I had a function like this:
``public List GetFoosBy(QueryGroup qGroup)
{
var pred = parseQueryGroup(qGroup);
ret
Solution
String requires string.Compare
Not true. There's a more generic option:
That will handle
Your treatment of
Not true. There's a more generic option:
if (typeof(IComparable).IsAssignableFrom(newSelector.Type))
{
switch (condition.Item2)
{
case CompareTypes.Equals:
expression = (ex, value) => value.CompareTo(cond.Item3) == 0;
break;
case CompareTypes.GreaterThan:
expression = (ex, value) => value.CompareTo(cond.Item3) > 0;
break;
case CompareTypes.LessThan:
expression = (ex, value) => value.CompareTo(cond.Item3) < 0;
break;
default:
throw new Exception("Unrecognized compare type");
}
...That will handle
string, char, DateTime, all numeric types, ... (NB I haven't tried compiling it: you might need to add suitable casts to IComparable inside the expressions).Your treatment of
DateTime will require special-casing. One option would be to put that before IComparable in the if-chain. Another might be to apply a projection before applying the comparison; for most types it would be the identity projection, but for DateTime it would be x => x.Date.Code Snippets
if (typeof(IComparable).IsAssignableFrom(newSelector.Type))
{
switch (condition.Item2)
{
case CompareTypes.Equals:
expression = (ex, value) => value.CompareTo(cond.Item3) == 0;
break;
case CompareTypes.GreaterThan:
expression = (ex, value) => value.CompareTo(cond.Item3) > 0;
break;
case CompareTypes.LessThan:
expression = (ex, value) => value.CompareTo(cond.Item3) < 0;
break;
default:
throw new Exception("Unrecognized compare type");
}
...Context
StackExchange Code Review Q#41661, answer score: 3
Revisions (0)
No revisions yet.