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

NHibernate左连接查询抛出System.NotImplementedException异常求助

左连接查询抛出System.NotImplementedException异常排查

问题描述

尝试在TaxInformation表和ThirdParty表之间执行左连接查询,普通连接可正常运行,但左连接时抛出异常,异常信息:

System.NotImplementedException: 'The method or operation is not implemented.'

相关查询代码

var TaxInformations = session.Query<TaxInformation>();

var query = session.Query<ThirdParty>()
                   .Where(tpa => tpa.ThirdPartySourceId == 1);

var resultList = (from tpn in query
                  join tti in TaxInformations on tpn.Id equals tti.ThirdPartyId into ttiLeft
                  from ttiL in ttiLeft.DefaultIfEmpty()
                  select new ThirdParty()
                  {
                      Id = tpn.Id,
                      LastName = tpn.LastName,
                      FirstName = tpn.FirstName,
                      DateOfBirth = tpn.DateOfBirth,
                      LegalContactPostalAddressId = tpn.LegalContactPostalAddressId,
                      BirthCityId = tpn.BirthCityId,
                      BirthCityName = tpn.BirthCityName,
                      Code = tpn.Code,
                      ContactPostalAdress = tpn.ContactPostalAdress,
                      TaxInformation = ttiL ?? null
                  }).ToList();
return resultList;

实体映射代码

TaxInformation映射

public ThirdPartyTaxInformationMap()
{
    this.Table("TaxInformation");
    this.Schema("dbo");
    this.Lazy(false);
    this.DynamicUpdate(true);
    this.DynamicInsert(true);           
    
    this.Id(x => x.Id, map => map.Generator(Generators.Identity));
    this.Property(x => x.ThirdPartyId);
    

    this.ManyToOne(
        x => x.Country,
        map =>
        {
            map.Column("CountryId");
            map.Cascade(Cascade.None);
            map.Lazy(LazyRelation.NoLazy);
            map.Fetch(FetchKind.Join);
            map.Update(false);
            map.Insert(false);
        }
        );
}

ThirdParty映射

public ThirdPartyMap()
{
    this.Table("ThirdParty");
    this.Lazy(false);
    this.DynamicUpdate(true);
    this.DynamicInsert(true);

    this.Id(x => x.Id, map => map.Generator(Generators.Identity));
    this.Property(x => x.Code, map => map.Column("Code"));
    this.Property(x => x.ThirdPartySourceId);
    

    this.ManyToOne(
        x => x.ContactPostalAdress,
        map =>
        {
            map.Column("LegalContactPostalAddressId");
            map.Cascade(Cascade.None);
            map.Lazy(LazyRelation.NoLazy);
            map.Fetch(FetchKind.Join);
            map.Update(false);
            map.Insert(false);
        });


    #region Third Party Type
    ManyToOne(p => p.ThirdPartyType, m =>
    {
        m.Class(typeof(ThirdPartyType));
        m.Column("ThirdPartyTypeId");
        m.NotNullable(false);
        m.Fetch(FetchKind.Join);
        m.Lazy(LazyRelation.NoLazy);
        m.Update(true);
        m.Insert(true);
    });
    #endregion
}

调用栈信息

at NHibernate.Linq.Visitors.QueryModelVisitor.VisitGroupJoinClause(GroupJoinClause groupJoinClause, QueryModel queryModel, Int32 index)
at Remotion.Linq.Clauses.GroupJoinClause.Accept(IQueryModelVisitor visitor, QueryModel queryModel, Int32 index)
at Remotion.Linq.QueryModelVisitorBase.VisitBodyClauses(ObservableCollection`1 bodyClauses, QueryModel queryModel)
at Remotion.Linq.QueryModelVisitorBase.VisitQueryModel(QueryModel queryModel)
at NHibernate.Linq.Visitors.QueryModelVisitor.Visit()
at NHibernate.Linq.Visitors.QueryModelVisitor.GenerateHqlQuery(QueryModel queryModel, VisitorParameters parameters, Boolean root, Nullable`1 rootReturnType)
at NHibernate.Linq.NhLinqExpression.Translate(ISessionFactoryImplementor sessionFactory, Boolean filter)
at NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory)
at NHibernate.Engine.Query.QueryPlanCache.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters)
at NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow)
at NHibernate.Impl.AbstractSessionImpl.CreateQuery(IQueryExpression queryExpression)
at NHibernate.Linq.DefaultQueryProvider.PrepareQuery(Expression expression, IQuery& query)
at NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression)
at NHibernate.Linq.DefaultQueryProvider.Execute[TResult](Expression expression)
at Remotion.Linq.QueryableBase`1.GetEnumerator()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at Oddo.MAP.Server.Modules.Core.Business.ThirdPartyBusinessServices.FindAllThirdpartyNatural() in C:\projets\MAP_Old\Server\Modules\Core\Server.Modules.Core.Business\ThirdPartyBusinessServices.cs:line 251
at Oddo.MAP.Server.Modules.Core.Business.ThirdPartyBusinessServices.CheckMatchingForThirdParties(Boolean isThirdPartyNatural) in C:\projets\MAP_Old\Server\Modules\Core\Server.Modules.Core.Business\ThirdPartyBusinessServices.cs:line 565
at DynamicModule.ns.Wrapped_IThirdPartyBusinessServices_fcf8cfddd9494f5898ae07beeb4a9d19.<CheckMatchingForThirdParties_DelegateImplementation>__2(IMethodInvocation inputs, GetNextInterceptionBehaviorDelegate getNext)
--- End of stack trace from previous location ---
at DynamicModule.ns.Wrapped_IThirdPartyBusinessServices_fcf8cfddd9494f5898ae07beeb4a9d19.CheckMatchingForThirdParties(Boolean isThirdPartyNatural)
at Oddo.MAP.Host.Dedoublonnage.Console.AppBootstrapper.OnModulesLoaded() in C:\projets\MAP_Old\Host\Host.Dedoublonnage\Program.cs:line 78
at Oddo.Components.Hosting.Unity.WebApi.WebApiHostingUnityBootstrapper.Initialize()
at Oddo.MAP.Host.Dedoublonnage.Console.AppBootstrapper.Initialize() in C:\projets\MAP_Old\Host\Host.Dedoublonnage\Program.cs:line 43
at Oddo.MAP.Host.Dedoublonnage.Console.Program.Main(String[] args) in C:\projets\MAP_Old\Host\Host.Dedoublonnage\Program.cs:line 26

异常原因

从调用栈可以明确,异常源于当前使用的NHibernate版本的Linq Provider未实现GroupJoinClause的解析逻辑——也就是代码中Linq语法的左连接写法(join ... into ... DefaultIfEmpty()本质是GroupJoin操作),早期NHibernate版本对Linq的GroupJoin支持存在缺陷或完全未实现。

解决方法

1. 使用NHibernate原生QueryOver实现左连接

QueryOver是NHibernate原生的强类型查询API,对左连接支持完善,示例代码:

// 定义别名变量
TaxInformation ttiAlias = null;
ThirdParty resultAlias = null;

var resultList = session.QueryOver<ThirdParty>()
    .Where(tpa => tpa.ThirdPartySourceId == 1)
    // 左连接TaxInformation表
    .Left.JoinQueryOver<TaxInformation>(t => t.TaxInformation, () => ttiAlias, 
        Restrictions.EqProperty("Id", "ttiAlias.ThirdPartyId"))
    // 构造返回结果
    .SelectList(list => list
        .Select(t => t.Id).WithAlias(() => resultAlias.Id)
        .Select(t => t.LastName).WithAlias(() => resultAlias.LastName)
        .Select(t => t.FirstName).WithAlias(() => resultAlias.FirstName)
        .Select(t => t.DateOfBirth).WithAlias(() => resultAlias.DateOfBirth)
        .Select(t => t.LegalContactPostalAddressId).WithAlias(() => resultAlias.LegalContactPostalAddressId)
        .Select(t => t.BirthCityId).WithAlias(() => resultAlias.BirthCityId)
        .Select(t => t.BirthCityName).WithAlias(() => resultAlias.BirthCityName)
        .Select(t => t.Code).WithAlias(() => resultAlias.Code)
        .Select(t => t.ContactPostalAdress).WithAlias(() => resultAlias.ContactPostalAdress)
        .Select(() => ttiAlias).WithAlias(() => resultAlias.TaxInformation)
    )
    // 将查询结果映射到ThirdParty实体
    .TransformUsing(Transformers.AliasToBean<ThirdParty>())
    .List<ThirdParty>();

2. 升级NHibernate版本

如果项目依赖允许,将NHibernate升级到5.0及以上版本,新版本的Linq Provider已经完善了GroupJoin的支持,可以直接兼容当前的Linq左连接写法,无需修改查询代码。

3. 利用实体关联导航实现左连接加载

在ThirdParty实体中添加TaxInformation的导航属性(若未配置),并完善映射关系(比如OneToOne或ManyToOne,根据实际业务关系),之后可以直接通过Fetch左连接加载关联数据:

var resultList = session.Query<ThirdParty>()
    .Where(tpa => tpa.ThirdPartySourceId == 1)
    .FetchLeftJoin(t => t.TaxInformation)
    .ToList();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 01:59:53