EF8多列唯一索引扩展方法的Linq表达式兼容问题及原理咨询
EF 8多列唯一索引扩展方法的表达式转换问题
我在EF 8(.NET 8)中编写了一个扩展方法,用于更便捷地添加多列唯一索引。EF内置的EntityTypeBuilder<TEntityType>.HasIndex方法,基于字符串的重载使用不便,而支持表达式语法的重载仅允许创建单列索引,因此我实现了如下扩展方法:
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); }
当调用该方法传入Int64类型属性时,代码运行正常:
builder .HasIndexUnique ( "Index_IndexName_Unique", e => e.ModelId, e => e.ModelEntityPrincipleId, e => e.ModelEntityDependentId, e => e.ModelEntityBridgeId );
但传入String类型属性时,表达式转换会抛出异常:
builder.HasIndexUnique("Index_IndexName_Unique", e => e.Name); // 异常发生在这一行: ((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[]类型属性的表达式转换逻辑,避免异常;
- 理解为什么Int64和String类型属性对应的表达式类型分别是
UnaryExpression和PropertyExpression?
附实体类代码:
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; } }
内容的提问来源于stack exchange,提问作者Raheel Khan
相关产品推荐
相关产品推荐

