【问题标题】:Convert Expression<Func<T1, bool>> to Expression<Func<T2, bool>>将 Expression<Func<T1, bool>> 转换为 Expression<Func<T2, bool>>
【发布时间】:2020-11-27 09:55:39
【问题描述】:

我正在使用存储库模式。 T1 是 T2 的 Dto(例如:UserDto 和 User)

在服务层,我通过Expression> 作为方法的参数,该方法本身调用其传递的数据访问层中的方法 表达式>.

现在,你可能会问我为什么不一直使用 Expression> 但我做不到。 是否可以进行表达式的转换? 请注意,User 和 UserDTO 具有相同的属性。

【问题讨论】:

  • 既然您已经添加了仍然需要能够将其与 EntityFramework 一起使用的要求,我认为这可能是您正在寻找的答案:stackoverflow.com/a/14933106/10608418。没有用 EF 对此进行测试,但由于它不使用不可翻译的方法调用,它可能只是工作。 Gl 与您的项目!
  • 他们的目标是将它与 EF 一起使用。这个答案看起来很棒。我会深入研究它,当我有结论时回复。谢谢
  • 在哪里可以确认这是否适用于 EF?
  • 它适用于简单的表达式。它甚至在答案中提到它。它需要扩展为更复杂的 expr,例如 x.Child1.Prop 等

标签: c# repository-pattern


【解决方案1】:

可以,只要您有将 T2 转换为 T1 的方法。这是一个简单的玩具示例,其中 T2 是 string,T1 是 int

        // That's the conversion function from T2 to T1
        private static int stringToInt(string s) => s.Length;

        [TestMethod]
        public void Test()
        {
            // We want to convert this into string->bool
            Expression<Func<int, bool>> isEven = i => i % 2 == 0;

            MethodInfo stringToIntMethod = ((Func<string, int>) (stringToInt)).Method;

            ParameterExpression x = Expression.Parameter(typeof(string));

            // That's the converted expression
            Expression<Func<string, bool>> converted =
                Expression.Lambda<Func<string, bool>>(
                    Expression.Invoke(isEven,
                        Expression.Call(null, stringToIntMethod, x)), x);

            // Check that it works as expected:
            converted.Compile().Invoke("aa").Should().BeTrue();
            converted.Compile().Invoke("aaa").Should().BeFalse();
        }

如果您打算将表达式与 LINQ 提供程序(例如 Entity Framework 或 Cosmos DB)一起使用,则必须确保支持包括转换调用在内的整个表达式。如果它是您定义的方法,则通常不是这种情况。

如果这应该是问题,你能在 T1 和 T2 上强加一个公共接口或基类吗?在这种情况下,您可以在两个层上传递Expression&lt;Func&lt;BaseClass, bool&gt;&gt; 类型的表达式而无需转换。如果做不到这一点(例如,如果 T1 和 T2 完全不同),实现您想要的唯一方法是分析表达式的结构并构建自定义表达式转换器(例如使用ExpressionVisitor)。

【讨论】:

  • 谢谢。我会花时间检查一下
  • 这个新表达式是否仍然适用于采用 Expression 并将其转换为其他代码的适配器? (如 EntityFramework)。提到存储库模式 imo 强烈暗示该表达式可能用于翻译。
  • @Knoop 否,除非 LINQ 提供程序具有对转换方法的内置支持。
  • 是的,我打算将它与 EF 一起使用。遗憾的是,LINQ to Entities 不支持 LINQ 表达式节点类型“Invoke”。
  • @Ergis 那是因为没有办法将任意自定义代码(您的转换方法)转换为 SQL。
猜你喜欢
  • 1970-01-01
  • 2017-06-01
  • 1970-01-01
  • 2021-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多