引用类的属性使用表达式,然后在LINQ查询中使用该表达式。

huangapple go评论69阅读模式
英文:

Refer to a class's property with an Expression, then use that Expression in a LINQ query

问题

我需要能够通过表达式引用对象的属性,我是这样做的:

Expression<Func<MyFirstModel, object>> MyFirstModelIdProperty = x => x.Id;

Intellisense 允许我这样做,但我不确定这是否是正确的声明。

现在,我正在尝试在 LINQ 表达式中实际使用属性引用:

int id = 500;
myFirstModelDataSet.SingleOrDefault(x => MyFirstModelIdProperty.Compile()(x) == id);

显然,这甚至无法编译,但我不确定该怎么做。

最终,我还将不得不支持这种情况:

Expression<Func<MyFirstModel, object>> MyFirstModelIdProperty = x => x.Id;
Expression<Func<MySecondModel, object>> MySecondModelIdProperty = x => x.TheId;

MySecondModel secondModel = new MySecondModel() { TheId = 55 };
myFirstModelDataSet.SingleOrDefault(x => MyFirstModelIdProperty.Compile()(x) == MySecondModelIdProperty.Compile()(secondModel));

最终目标是希望用户能够告诉我的项目如何通过“id”查询 DbSet,而无需明确指定属性(通过字符串)。

英文:

I need to be able to refer to an object's property through an Expression, which I do in this way:

Expression&lt;Func&lt;MyFirstModel, object&gt;&gt; MyFirstModelIdProperty = x =&gt; x.Id;

Intellisense is allowing me to do this, but I don't know for sure that's the correct declaration.

Now, I'm trying to actually use the property reference in a LINQ expression

int id = 500;
myFirstModelDataSet.SingleOrDefault(x=&gt; MyFirstModelIdProperty == id); //??

Obviously, this isn't even compiling but I'm not sure how to go about.

Eventually, I'll have to also support this case

Expression&lt;Func&lt;MyFirstModel, object&gt;&gt; MyFirstModelIdProperty = x =&gt; x.Id;
Expression&lt;Func&lt;MySecondModel, object&gt;&gt; MySecondModelIdProperty = x =&gt; x.TheId;

MySecondModel secondModel = new MySecondModel() { TheId = 55 };
myFirstModelDataSet.SingleOrDefault(x=&gt; MyFirstModelIdProperty == MySecondModelIdProperty); //??

The end goal here is that I want people to be able to inform my project how to query a DbSet by "id" without having to specify the properties literally (through strings).

Any ideas ?

答案1

得分: 2

假设您正在使用`IQueryable`(否则只需编译表达式),最简单的方法是使用[LINQKit][1]

```csharp
myFirstModelDataSet.AsExpandable().SingleOrDefault(x => MyFirstModelIdProperty.Invoke(x) == (object)id);

否则,您将需要自己执行一些表达式树编译:

int someId = 42;
var equalExp = Expression.Equal(MyFirstModelIdProperty.Body, Expression.Convert(Expression.Constant(someId), typeof(object)));
var expression = Expression.Lambda<Func<Person, bool>>(equalExp, MyFirstModelIdProperty.Parameters);
myFirstModelDataSet.SingleOrDefault(expression);

对于第二个,您需要执行参数替换,可以使用ReplacingExpressionVisitor 轻松完成。大致如下:

var secondOp = new ReplacingExpressionVisitor(MySecondModelIdProperty.Parameters, MyFirstModelIdProperty.Parameters)
        .Visit(MySecondModelIdProperty.Body);

var equalExp = Expression.Equal(MyFirstModelIdProperty.Body, secondOp);

<details>
<summary>英文:</summary>

Assuming your are working with `IQueryable`(otherwise just compile expression) - the easiest option would be to use [LINQKit][1]:

```csharp
myFirstModelDataSet.AsExpandable().SingleOrDefault(x=&gt; MyFirstModelIdProperty.Invoke(x) == (object)id);

Otherwise you will need to perform some expression tree compilation yourself:

int someId = 42;
var equalExp = Expression.Equal(MyFirstModelIdProperty.Body, Expression.Convert(Expression.Constant(someId), typeof(object)));
var expression = Expression.Lambda&lt;Func&lt;Person, bool&gt;&gt;(equalExp, MyFirstModelIdProperty.Parameters);
myFirstModelDataSet.SingleOrDefault(expression);

For the second one you will need to perform parameter replacement which can easily be done with ReplacingExpressionVisitor. Something along these lines:

var secondOp = new ReplacingExpressionVisitor(MySecondModelIdProperty .Parameters, MyFirstModelIdProperty.Parameters)
        .Visit(MySecondModelIdProperty.Body);

var equalExp = Expression.Equal(MyFirstModelIdProperty.Body, secondOp);

huangapple
  • 本文由 发表于 2023年4月13日 22:01:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/76006360.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定