EF dynamic query with enum - linq

I'm trying to build a dynamic query whit a condition on an emum
enumField & enumValue == enumValue
for this, during the analysis the following is called
Expression GenerateBitWiseAnd(Expression left, Expression right) {
return Expression.And(left, right);
}
this throws an exception
And binary operator is not defined for `EnumType` and `EnumType`.
The equality operator runs well
Expression GenerateEqual(Expression left, Expression right) {
return Expression.Equal(left, right);
}
But I can't figure how to handle a [Flags] without the And bits operator.
The question is: from here how to dynamically forge my query to check my enum.
My application is targeting .Net 4

You'll need to convert the Enum to its underlying type before you can operate on it:
Expression GenerateBitWiseAnd(Expression left, Expression right)
{
if (left.Type.IsEnum)
{
var enumType = left.Type;
var compareType = Enum.GetUnderlyingType(enumType);
var enumField = Expression.Convert(left, compareType);
var enumValue = Expression.Convert(right, compareType);
var and = Expression.And(enumField, enumValue);
return Expression.Convert(and, enumType);
}
return Expression.And(left, right);
}

Related

Spring Data JPA How to use Predicate in Specifiaction

I would like to create Specification to dynamic search.
In database I have fields like radius, width and height - depends on type of shape.
I want to add request paramter like for example areaTo - which will be returing shapes with area smaller or equal to paramter.
I was thinking about adding some Predicate but I can not find any example how to do it.
What I mean, I would like to add something like that:
public static Specification<ShapeEntity> areaTo(double areaTo) {
return (root, query, criteriaBuilder) -> {
double area;
switch (root.get("type").toString()) {
case "CIRCLE":
area = Math.pow(Double.parseDouble(root.get("radius").toString()), 2) * Math.PI;
break;
case "RECTANGLE":
area = Double.parseDouble(root.get("width").toString()) * Double.parseDouble(root.get("height").toString());
break;
case "SQUARE":
area = Math.pow(Double.parseDouble(root.get("width").toString()), 2);
break;
default:
throw new IllegalArgumentException();
}
return criteriaBuilder.lessThanOrEqualTo(????, areaTo);
};
}
I found a solution that somewhat answers your question, what you need to create here is an Expression.
you could try to modify this code to suit what you need:
private Specification<Shape> areaTo(double areaTo, String type) {
return (root, query, criteriaBuilder) -> {
Expression<Double> area;
switch (type) {
case "CIRCLE":
Expression<Double> radius = root.get("radius");
Expression<Double> power = criteriaBuilder.prod(radius, radius);
area = criteriaBuilder.prod(power, Math.PI);
break;
case "RECTANGLE":
Expression<Double> width = root.get("width");
Expression<Double> height = root.get("height");
area = criteriaBuilder.prod(width, height);
break;
case "SQUARE":
Expression<Double> width_s = root.get("width");
area = criteriaBuilder.prod(width_s, width_s);
break;
default:
throw new IllegalArgumentException();
}
return criteriaBuilder.lessThanOrEqualTo(area, areaTo);
};
}
your switch (root.get("type").toString()) won't work in the switch statement because there is no value return here, they creating a query. In this situation, you could create a Predicate for each type of shape and then add them to criteriaBuilder with operator or
for further information about my solution you should take a look at this link

Extension method with generic Func parameter of other type

Is there a way to implement an extension method to a generic type that takes in arguments a Func of another type?
For exemple, a usage something similar to this:
myFirstObject.Extension<myOtherObject>( other => other.Prop );
Or with a more complicated Func:
myFirstObject.Extension<myOtherObject>( other => other.Prop > 2 && other.Prop < 15 );
I found some related question like this one, but in my case, I need generic types inside the extension method too.
Here's what I came up with:
public static bool Extension<TSource, TIn, TKey>(this TSource p_Value, Expression<Func<TIn, TKey>> p_OutExpression)
{ return true; }
However, when I try to use it, it does not take into consideration the second type.
Am I missing something?
Look at this:
s => s.Length;
How's the compiler suppose to know whether or not s is a string or s is an array or some other type that has a Length property? It can't, unless you give it some information:
(string s) => s.Length;
Oh, there we go. So now, try this:
myFirstObject.Extension((myOtherObject o) => o.Prop > 2 && o.Prop < 15);
That will work, because you've told the compiler what it should use for TIn, and it can figure out what to use for TKey based on the expression.
I found that another solution would be to create another method that takes in argument a type.
For instance:
Void Extension(Type p_Type, [THE TYPE] p_Params)
{
MethodInfo realExtensionMethod = typeof([CLASS CONTAINING THE METHOD]).GetMethod("RealExtension");
realExtensionMethod = realExtensionMethod.MakeGenericMethod(p_Type);
realExtensionMethod.Invoke(null, new object[] {p_Type, p_Params });
}
Void RealExtension<TYPE>(params)
{
}
Then at usage time:
Type objectType = typeof(myOtherObject);
myFirstObject.Extension(objectType, other => other.Prop );
When you call a generic method in C# you can explicitly declare all of the generic type parameters or you can have them all inferred, but you cannot have some explicitly declared and some inferred.
So, if I had this method:
public void Foo<X, Y>(X x, Y y)
{
/* Do somethhing */
}
Then here's what works and what doesn't:
int a = 42;
string b = "Hello, World!";
// Legal
Foo(a, b);
Foo<int, string>(a, b);
//Illegal
Foo<int>(a, b);
The best you can do is move the first generic parameter up to the class level, but not it won't work as an extension method. Nevertheless you may like this approach.
public static class Class<TSource>
{
public static bool Method<TIn, TKey>(
TSource p_Value,
Expression<Func<TIn, TKey>> p_OutExpression)
{
return true;
}
}
Now you can call it like this:
Expression<Func<long, decimal>> f =
l => (decimal)l;
var result = Class<int>.Method(a, f);
But as I say, it won't work as an extension method now.

"..cannot be inferred from the usage." How can I insert both a where and an orderby expression into this sqlite query?

I've been following the Tasky Case Study on the MonoDroid website, but I've run into a wall whilst creating a filtering and ordering query. I was wondering if somebody could explain where I might be going wrong please? I'm probably doing something completely backwards!
I get the error:
The type arguments for method 'ICanTalk.BusinessLayer.Services.WordServices.Find(System.Func, System.Func, bool, int, int)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
I have the following code in one of my repositories, hopefully what I'm trying to do is kind of clear. I haven't been able to build it yet to test to see if it works though:
public static IEnumerable<Word> Find<T,U>(Func<Word, bool> whereClause, Func<Word,U> orderBy, bool ascending, int show, int page)
{
int currentPage = page;
int resultsPerPage = show;
int skip = currentPage*show;
var result = ascending
? me.db.Find<Word>().Where(whereClause).OrderBy(orderBy).Take(resultsPerPage).Skip(skip)
: me.db.Find<Word>().Where(whereClause).OrderByDescending(orderBy).Take(resultsPerPage).Skip(skip);
return result;
}
From my services I call this method from here:
public static IList<Word> Find<T>(Func<Word, bool> whereClause, Func<Word,DateTime> orderBy, bool ascending, int show, int page)
{
return WordRepository.Find<Word, DateTime>(whereClause, orderBy, ascending, show, page).ToList();
}
What I'm trying to achieve is a call from an event handler within MonoDroid like:
var wordTest = WordServices.Find(x => x.ChildId == 3, x => x.AddedAt, true, 5, 1);
Both of your methods are generic Find<T,U> and Find<T> - but you don't seem to be using the type T anywhere in your method definition. Was T expected to be the type Word ?
U is used once in the orderBy where elsewhere you're using bool - which of those usages is a mistake?
Can you try replacing Word with T in your definitions, and bool with U (if that's what you meant to do) and then when you're calling the method actually call it with the correct type ?
var wordTest = WordServices.Find<Word>(x => x.ChildId == 3,
x => x.AddedAt,
true, 5, 1);
I had it almost right, I stripped it down to the basics and worked my way back up and came up with the following (compare to original if you're interested).
SQLiteDatabase.cs
(not in original post - I scaled the query clauses right down to a reusable method in my generic handler):
public IEnumerable<T> Find<T>(Func<T, bool> whereClause, int resultsToSkip, int resultsToShow)
where T : BusinessLayer.Contracts.IBusinessEntity, new()
{
lock (locker)
{
return Table<T>().Where(whereClause).Skip(resultsToSkip).Take(resultsToShow).ToList();
}
}
WordRepository.cs
public static IEnumerable<Word> Find<T>(Func<Word, bool> whereClause, int resultsToSkip, int resultsToShow)
where T : BusinessLayer.Contracts.IBusinessEntity, new()
{
var result = me.db.Find<Word>(whereClause, resultsToSkip, resultsToShow);
return result;
}
WordServices.cs
By this point I'm wondering why there exists a need for so many layers - will definitley look to refactor in the morning.
public static IList<Word> Find<T, U>(Func<Word, bool> whereClause, Func<Word, U> orderBy, bool ascending, int show, int page)
{
int resultsToShow = show;
int resultsToSkip = show * (page - 1);
var result = ascending ? WordRepository.Find<Word>(whereClause, resultsToSkip, resultsToShow).OrderBy(orderBy)
: WordRepository.Find<Word>(whereClause, resultsToSkip, resultsToShow).OrderByDescending(orderBy);
return result.ToList();
}
Originating Call
var wordTest1 = WordServices.Find<Word, DateTime>(x => x.ChildId == 1, x => x.AddedAt, true, 5, 1);

LINQ with non-lambda for Any Contains

How do you do Linq with non-lambda express for the following (which does not work):
string[] words = { "believe", "relief", "receipt", "field" };
var wd = (from word in words
select word).Any(Contains ("believe"));
It's not clear what good you believe the from wor in words select wor is doing - it's really not helping you at all.
It's also not clear why you don't want to use a lambda expression. The obvious approach is:
bool hasBelieve = words.Any(x => x.Contains("believe"));
Note that this isn't checking whether the list of words has the word "believe" in - it's checking whether the list of words has any word containing "believe". So "believer" would be fine. If you just want to check whether the list contains believe you can just use:
bool hasBelieve = words.Contains("believe");
EDIT: If you really want to do it without a lambda expression, you'll need to basically fake the work that the lambda expression (or anonymous method) does for you:
public class ContainsPredicate
{
private readonly string target;
public ContainsPredicate(string target)
{
this.target = target;
}
public bool Apply(string input)
{
return input.Contains(target);
}
}
Then you can use:
Func<string, bool> predicate = new ContainsPredicate("believe");
bool hasBelieve = words.Any(predicate);
Obviously you really don't want to do that though...
EDIT: Of course you could use:
var allBelieve = from word in words
where word.Contains("believe")
select word;
bool hasBelieve = allBelieve.Any();
But that's pretty ugly too - I'd definitely use the lambda expression.
You could do it like that
string[] words = { "believe", "relief", "receipt", "field" };
var wd = (from wor in words
where wor.Contains("believe")
select wor);

Expression.Default in .NET 3.5

How can I emulate Expression.Default (new in .NET 4.0) in 3.5?
Do I need to manually check the expression type and use different code for reference and value types?
This is what I'm currently doing, is there a better way?
Expression GetDefaultExpression(Type type)
{
if (type.IsValueType)
return Expression.New(type);
return Expression.Constant(null, type);
}
The way you did it is good. There is no Type.GetDefaultValue() method built in to the .NET Framework as one would expect, so the special case handling for value types is indeed necessary.
It is also possible to produce a constant expression for value types:
Expression GetDefaultExpression(Type type)
{
if (type.IsValueType)
return Expression.Constant(Activator.CreateInstance(type), type);
return Expression.Constant(null, type);
}
The advantage of this I suppose would be that the value type is only instanciated once, when the expression tree is first built, rather than every time the expression is evaluated. But this is nitpicking.
How about using an extension method?
using System;
using System.Linq.Expressions;
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
Type t = typeof(int);
Expression e = t.Default(); // <-----
Console.WriteLine(e);
t = typeof(String);
e = t.Default(); // <-----
Console.WriteLine(e);
Console.ReadLine();
}
}
public static class MyExtensions
{
public static Expression Default(this Type type)
{
if (type.IsValueType)
return Expression.New(type);
return Expression.Constant(null, type);
}
}
}

Resources