You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 10中NHibernate使用数组Contains方法查询报错求助

解决.NET 10中NHibernate数组Contains查询报错问题

问题背景

在.NET 9中正常运行的NHibernate Linq查询,使用数组的Contains方法过滤Staff实体时,升级到.NET 10后抛出以下错误:

NHibernate.HibernateException: 'Evaluation failure on op_Implicit(value(System.Int64[]))'

改用List<long>类型的集合则可正常执行,但不想批量修改代码中的数组定义。


解决方案

方案1:查询内临时转换数组为IEnumerable

无需修改数组的定义,只需在Contains调用前通过AsEnumerable()将数组转为IEnumerable<long>,NHibernate可以正常解析Enumerable.Contains方法:

var ids1 = new long[] { 1, 2, 3 };
var result1 = session.Query<Staff>().Where(x => ids1.AsEnumerable().Contains(x.Id)).ToList();

方案2:添加全局扩展方法简化调用

如果项目中有多处类似场景,可编写一个扩展方法避免重复编写AsEnumerable():

public static class ArrayQueryExtensions
{
    public static IEnumerable<T> ForNHibernateQuery<T>(this T[] array)
    {
        return array.AsEnumerable();
    }
}

使用示例:

var result1 = session.Query<Staff>().Where(x => ids1.ForNHibernateQuery().Contains(x.Id)).ToList();

方案3:全局配置NHibernate支持数组Contains(进阶)

如果希望从框架层面彻底解决,无需修改任何业务查询代码,可以自定义NHibernate的Linq表达式解析逻辑,注册数组类型的Contains方法支持:

  1. 创建自定义的HQL生成器,处理数组的Contains方法:
using NHibernate.Linq.Functions;
using System.Linq.Expressions;
using System.Reflection;

public class ArrayContainsHqlGenerator : BaseHqlGeneratorForMethod
{
    public ArrayContainsHqlGenerator()
    {
        // 注册要处理的数组Contains方法
        var containsMethod = typeof(long[])
            .GetMethod(nameof(Array.Contains), new[] { typeof(long) })!
            .GetGenericMethodDefinition();
        SupportedMethods = new[] { containsMethod };
    }

    public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
    {
        // 将数组转为IEnumerable,复用NHibernate已有的Contains解析逻辑
        var enumerableExpr = Expression.Call(
            typeof(Enumerable), 
            nameof(Enumerable.AsEnumerable), 
            new[] { method.DeclaringType!.GetElementType()! }, 
            targetObject);
        
        var enumerableContainsMethod = typeof(Enumerable)
            .GetMethod(nameof(Enumerable.Contains), new[] 
            { 
                typeof(IEnumerable<>).MakeGenericType(method.DeclaringType.GetElementType()!),
                method.DeclaringType.GetElementType()! 
            })!;
        
        return visitor.Visit(Expression.Call(enumerableContainsMethod, enumerableExpr, arguments[0])).AsExpression();
    }
}
  1. 注册自定义生成器到NHibernate配置:
using NHibernate.Cfg;
using NHibernate.Linq.Functions;

public class CustomLinqToHqlRegistry : DefaultLinqToHqlGeneratorsRegistry
{
    public CustomLinqToHqlRegistry()
    {
        Merge(new ArrayContainsHqlGenerator());
    }
}

// 在NHibernate初始化时配置
var config = new Configuration();
config.LinqToHqlGeneratorsRegistry<CustomLinqToHqlRegistry>();

配置完成后,原有的数组Contains查询无需任何修改即可在.NET 10中正常运行。


内容的提问来源于stack exchange,提问作者Craig

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.11 19:34:54