0

Let's assume we have a variable called TOTAL and it should be replaced with AProperty + BProperty of CClass. I have an IQueryrable set of CClass objects and I want to select (TOTAL + AProperty) from this set.

AProperty and BProperty are double values. I don't want to extend my class because it's an entity class in my DB and actually the TOTAL expression is a runtime, user defined variable. So I don't want to inject them by Reflection or some other solutions. I want to give capability to end user to declare some MACRO-liked variables to create more complicated expressions based on them.

Is there any way that I can define TOTAL expression for my interpreter according to above scenario?

Amin Mozhgani
  • 604
  • 1
  • 7
  • 22
  • what do you mean by "replaced" ? could you please examplify it with code? – Mong Zhu Aug 29 '18 at 05:35
  • I need to run dynamic expressions over an IQueryable set. It's a set of CClass type and this type has two properties called AProperty and BProperty. I need to define some predefined expressions; for example TOTAL variable that is an expression : (AProperty + BProperty). So when I enter "TOTAL + AProperty" as input expression in my select expression, it should be calculated as "AProperty + BProperty + BProperty). Indeed the TOTAL variable is an expression itself. It's like a reserved variable that is an expression. – Amin Mozhgani Aug 29 '18 at 05:40
  • why does it have to be an expression? it sounds like an explicit property getter would suffice. Like: `{ return AProperty + BProperty; }` you can extend your `CClass` using the partial key word. Do you want the calculation to happen on the server and not in memory? – Mong Zhu Aug 29 '18 at 05:44
  • what type is `AProperty` and `BProperty` ? – Mong Zhu Aug 29 '18 at 05:47
  • 1
    AProperty and BProperty are double values. I don't want to extend my class because it's an entity class in my DB and actually the TOTAL expression is a runtime, user defined variable. So I don't want to inject them by Reflection or some other solutions. I want to give capability to end user to declare some MACRO-liked variables to create more complicated expressions based on them. – Amin Mozhgani Aug 29 '18 at 05:52
  • ok, may be you should include your last comment into your post. sounds like very important information – Mong Zhu Aug 29 '18 at 06:04
  • I have see the same question in github, see my response here: https://github.com/davideicardi/DynamicExpresso/issues/84 P.S. I suggest to post questions to a single site/forum/... – Davide Icardi Aug 29 '18 at 16:26
  • There are probably dozens of ways, for example, you could substitute the macro expansion (adding parentheses) in the textual input the user provides before interpreting the input (so e.g. `(TOTAL+AProperty)` becomes `(AProperty+BProperty+AProperty)`) before you run the query. In [this answer](https://stackoverflow.com/a/50071274/2557128), I show how to use `Regex` substitution to solve this. If you don't know how to run the expression without the macro against the `IQueryable`, that is a different question. – NetMage Aug 29 '18 at 20:38
  • Using Regex for replacing expressions into premitive properties is not what I want, because there are some scenarios that we should interpret those expressions recursively. For example if given THOTAL variable was made of another variable that is an expression itself, so the complexity of the regex based solution is high. – Amin Mozhgani Aug 30 '18 at 08:40

1 Answers1

0

You wrote:

we have a variable called TOTAL and it should be replaced with...

Alas, LINQ is meant to select data from a sequence. LINQ won't change the input sequence.

Luckily you also wrote:

I have an IQueryrable set of CClass objects and I want to select (TOTAL + AProperty) from this set.

Okay, we can do that.

I don't want to change my class...

Of course you don't want to change your entity classes: your entity classes represent the tables in your database and the relations between those table. Your function is not something that is typically something of your database tables. Therefore it doesn't belong there.

So instead of changing your entity classes we'll write a separate extension function for your entities. For users of your class it would look as if the function is part of the class. See Extension Methods demystified

I won't write the function for your IQueryable<CClass>, I'll write a function for any queryable sequence of objects

Input: a queryable sequence of objects of some type and a double value Value.
Also: a> property selector that selects a get-property of your objects that has a double value.
Output: the sum of Value and the value of the get-property.

public static double AddToProperty<TSource> (this IEnumerable<TSource> source, 
     Expression<Func<TSource, double>> propertySelector,        
     double value);
     where Tsource : class
{
     return source.Select(soureElement => propertySelector(sourceElement) + value);
}

Usage:

var addedTotals = myDbContext.Students
    .AddToPropery( student => student.AnnualIncome, 3.14);
Harald Coppoolse
  • 28,834
  • 7
  • 67
  • 116
  • Thanks for your detailed answer. The way you mentioned is good when we know about the operator (like + in this case). Consider we have a Textarea control and our end user writes his own formula based on all the properties exist in CClass. For example he can set TOTAL variable as (AProperty - (2*BProperty) and ... . So what I really want is a compiler-liked structure to map those string expressions into Linq queries. – Amin Mozhgani Sep 01 '18 at 04:08
  • If your operator types an expression as input, you'll have to check the expression at run-time. Obviously this can't be done at compile time. This expression can be used in an `IQueryable` You could decompose the expression to see if it can be performed, or you just use the expression. As soon as the `Provider` of your `IQueryable` tries to compile the `Expression` an exception will be ;thrown if the expression is incorrect. – Harald Coppoolse Sep 02 '18 at 20:53
  • Thanks, I know that I should check it run-time but as you know better that me we can define a variable that will be replaced with an expression at run-time by reflection. That was I want. – Amin Mozhgani Sep 03 '18 at 04:02