【问题标题】:Convert my value type to nullable equivalent将我的值类型转换为可为空的等价物
【发布时间】:2020-06-26 18:32:06
【问题描述】:

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

报告系统将允许返回 LEFT JOIN 结果的查询。连接表中有字段在数据库中为NOT NULL;但是因为这是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);

Dynamic LINQ 支持显式转换:

// using static System.Linq.Dynamic.Core

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

但查询中只能引用specific set of types。如果我尝试在查询中使用Color

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

我收到以下错误:

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

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

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

我明白了:

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

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

【问题讨论】:

  • 在枚举中为NONE添加一项
  • @jdweng 最终我需要这个来从 LEFT JOIN 获取所需列中的值;如果JOINed 表中没有相应的记录,则所述值将为NULL。此外,这对于非枚举值类型也无济于事。
  • 你是在数据库中存储枚举的名称还是在数据库中存储整数值?
  • @Saravanan 整数值。
  • 需要使用 LINQ 吗?

标签: c# linq dynamic-linq dynamic-linq-core


【解决方案1】:

Dynamic 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 中的输出:

【讨论】:

【解决方案2】:

试试这个:

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

【讨论】:

    【解决方案3】:

    我想建议你可以使用下面的sn -p来识别输入的数字是否是枚举的一部分。

    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);
    }
    

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

    【讨论】:

    • 问题在于没有识别输入值是否是枚举的一部分。问题(主要)是动态 LINQ 库的 AFAICT 无法说“将其转换为任意类型”,只有可识别的类型。如果没有动态 LINQ,这样做非常简单:Range(0, 3).Select(x =&gt; (Color)x).Select(x =&gt; (Color?)x),如果值碰巧与任何枚举值都不匹配,甚至不会出现运行时错误。
    • 好的,您是否尝试使用动态 linq,以便您可以将其应用于过滤器,例如查询您的数据库
    • 你是否打算做这样的事情:docs.microsoft.com/en-us/dotnet/api/…
    • 是的。我正在编写一个带有 LEFT JOIN 的查询,并且连接表中的某些行返回 NULL。连接表中的某些字段被键入为不可为空的值类型;但是当字段在 LEFT JOIN 中返回时,它们可以为 NULL。在将字符串传递给 Dynamic LINQ 时,它创建的表达式不考虑这些 NULL 值; Dynamic LINQ 识别的类型可以是“Nullable-ified”,但其他类型(例如自定义枚举)不能。我知道我可以重写生成的表达式树并修复它,但如果可能的话,我宁愿在 Dynamic LINQ 的约束下工作。
    • 我已经澄清了这个问题。
    猜你喜欢
    • 1970-01-01
    • 2015-06-17
    • 2016-05-23
    • 1970-01-01
    • 2016-07-09
    • 1970-01-01
    • 1970-01-01
    • 2017-05-04
    • 1970-01-01
    相关资源
    最近更新 更多