5

我有一个临时报告系统;我对查询的源类型或所需字段没有编译时知识。我可以在运行时使用工厂方法编写表达式树System.Linq.Expressions.Expression,并使用反射调用 LINQ 方法,但动态 LINQ 是一种更简单的解决方案。

报告系统将允许返回 LEFT JOIN 结果的查询。联接表中有字段在NOT NULL数据库中;但因为这是 a LEFT JOIN,所以这些字段将包含NULL某些记录。EF6 生成的表达式落在此之上,因为该表达式投影为不可为空的值类型。

如果我在编译时 LINQ 中执行此操作,我将显式转换为可空类型:

enum Color { Red, Green,  Blue }

// using System;
// using static System.Linq.Enumerable;
// using System.Linq;

var range = Range(0, 3).Select(x => (Color)x).AsQueryable();
var qry = range.Select(x => (Color?)x);

动态 LINQ 支持显式转换:

// using static System.Linq.Dynamic.Core

var qry1 = range.Select("int?(it)");

但查询中只能引用一组特定的类型。如果我尝试Color在查询中使用:

var qry2 = range.Select("Color(it)");

我收到以下错误:

“颜色”类型中不存在适用的方法“颜色”

如果我尝试显式转换为Color?

var qry3 = range.Select("Color?(it)");

我得到:

未找到请求的值“颜色”。

如何使用动态 LINQ 库来做到这一点?

4

3 回答 3

7

动态 LINQ 提供了一种Cast方法,可以按如下方式使用:

var range = Enumerable.Range(0,3).Select(x => (Color)x).AsQueryable();
var castDynamic = range.Cast(typeof(Color?)).ToDynamicArray();
castDynamic.Dump();

您还可以传递带有输出类型名称的字符串。请注意,对于可空类型,您需要类型的全名:

string s = typeof(Color?).FullName;
s.Dump();
var castDynamicFromString = range.Cast(s);
castDynamicFromString.Dump();

Cast也可以在动态 LINQ 字符串表达式中使用,或者将Type对象作为参数传递,或者直接使用名称:

var castInSelect = range.Select($@"Cast(""{s}""").ToDynamicArray();
castInSelect.Dump();

LINQPad 中的输出:

在此处输入图像描述

于 2020-03-18T08:30:50.340 回答
3

试试这个:

var arg0 = Expression.Parameter(typeof(Color), "x");
var expr = DynamicExpressionParser.ParseLambda(new[] { arg0 }, typeof(Color?), "x");
var qry2 = range.AsQueryable().Select("@0(it)", expr);

另请参阅https://github.com/StefH/System.Linq.Dynamic.Core/wiki/Dynamic-Expressions#dynamic-lambda-invocation

于 2020-03-18T12:04:33.243 回答
0

我想建议您可以使用以下代码段来识别输入数字是否是枚举的一部分。

public static bool IsValuePresent<T>(int number) where T : Enum
{
    return !Enum.GetValues(typeof(T)).Cast<int>().Contains(number);
}

以下可能是检查输入值是否存在于枚举中的调用

EnumerationConverter.IsValuePresent<Color>(99); //returns False
EnumerationConverter.IsValuePresent<Color>(2); //returns True

一旦在上述语句中获得了 False,我们可以将值设置为 null,否则,我们可以像下面给出的代码那样做一个从整数到枚举的简单泛型类型转换器。

public static T GetAsEnum<T>(int number) where T : Enum
{
    if (Enum.IsDefined(typeof(T), number))
    {
        return (T)Enum.ToObject(typeof(T), number);
    }
    return default(T);
}

基于您必须检查有效枚举值然后进行转换的理解,可以尝试上述解决方案,如果有任何其他方面,请在此处发布更新。

于 2020-03-16T13:24:04.173 回答