相应地检测和转换 Linq 表达式

问题描述 投票:0回答:1

我编写了一个扩展方法,以便更轻松地在 EF 8 (.NET 8) 中添加多列索引,如下所示:

public static IndexBuilder<TEntityType> HasIndexUnique<TEntityType>
(
    this EntityTypeBuilder<TEntityType> builder,
    string indexName,
    IEnumerable<Expression<Func<TEntityType, object?>>> includeExpressions
) where TEntityType : class
{
    if ((includeExpressions is null) || (!includeExpressions.Any()))
    {
        var currentMethod = MethodBase.GetCurrentMethod();
        throw (new Exception($@"The method [{currentMethod?.DeclaringType?.FullName}.{currentMethod?.Name}] was called without any [{nameof(includeExpressions)}]."));
    }

    var propertyNames = includeExpressions
        .Select
        (
            e =>
            // Casting issue depending on what was sent in.
            ((MemberExpression) ((UnaryExpression) e.Body).Operand).Member.Name
        )
        .ToArray();

    var indexBuilder = builder
        .HasIndex
        (
            propertyNames,
            $@"{indexName}"
        )
        .IsUnique(unique: true);

    return (indexBuilder);
}

EntityTypeBuilder<TEntityType>.HasIndex
的内置重载是基于
string
的(我认为这很笨重)。支持
Expression
语法的重载仅允许一列。上面的方法就像一个魅力,使调用代码更容易阅读。

builder
    .HasIndexUnique
    (
        "Index_IndexName_Unique",
        e => e.ModelId,
        e => e.ModelEntityPrincipleId,
        e => e.ModelEntityDependentId,
        e => e.ModelEntityBridgeId
    );

在上面的示例中,传入的所有属性都是

Int64
类型。当我尝试发送
String
属性时,表达式转换失败。

builder.HasIndexUnique("Index_IndexName_Unique", e => e.Name);

// Exception at this line:
((MemberExpression) ((UnaryExpression) e.Body).Operand).Member.Name
System.InvalidCastException: 'Unable to cast object of type 'System.Linq.Expressions.PropertyExpression' to type 'System.Linq.Expressions.UnaryExpression'.'

如何检测和处理不同类型的属性以便正确地转换它们?我已经预计了以下几种数据类型,这应该足够了:

Int64, String, DateTime, Object, Byte []

我希望有一个解决方案,但也想了解是什么使表达式成为一元或属性或我尚未探索的其他类型。

编辑

public partial class ModelEntityRelationship:
    IEntity<ModelEntityRelationship>
{
    public virtual long Id { get; set; }
    public virtual string Name { get; set; }

    public virtual long ModelId { get; set; }
    public virtual Model Model { get; set; }

    public virtual long ModelEntityPrincipleId { get; set; }
    public virtual ModelEntity ModelEntityPrinciple { get; set; } = new();

    public virtual long ModelEntityDependentId { get; set; }
    public virtual ModelEntity ModelEntityDependent { get; set; } = new();

    public virtual long? ModelEntityBridgeId { get; set; }
    public virtual ModelEntity? ModelEntityBridge { get; set; }
}

我添加了源实体类来澄清我的困惑来源。除了数据类型之外,所有属性声明都是相同的。那么为什么分别发送

Unary
Property
对象时,表达式类型会从
Int64
变为
String
呢?

c# .net entity-framework linq expression
1个回答
0
投票

我建议创建扩展方法,删除不需要的转换,这是通过转换为对象值类型添加的。

public static class ExpressionExtensions
{
    [return: NotNullIfNotNull(nameof(ex))]
    public static Expression? UnwrapConvert(this Expression? ex)
    {
        if (ex == null)
            return null;

        switch (ex.NodeType)
        {
            case ExpressionType.ConvertChecked :
            case ExpressionType.Convert        :
            {
                var unaryExpression = (UnaryExpression)ex;
                if (unaryExpression.Method == null)
                    return unaryExpression.Operand.UnwrapConvert();
                break;
            }
        }

        return ex;
    }
}

因此,在您的情况下,您可以简单地转换为

MemberExpression

((MemberExpression)e.Body.UnwrapConvert()).Member.Name
© www.soinside.com 2019 - 2024. All rights reserved.