From 691d080ef17c5a230f378bca5f38820b962946e8 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Fri, 9 Dec 2022 15:00:38 +0100 Subject: [PATCH 01/19] interfaces extracted for Dependency Inversion Principle - IQueryLoader - ILoader - ILinqQueryExpression --- build-common/NHibernate.props | 2 +- .../BulkManipulation/BaseFixture.cs | 18 ++- src/NHibernate.Test/Hql/Ast/BaseFixture.cs | 18 ++- .../NH2031/HqlModFuctionForMsSqlTest.cs | 18 ++- .../Hql/Ast/ANTLR/QueryTranslatorImpl.cs | 2 +- src/NHibernate/Async/Hql/IQueryTranslator.cs | 1 + src/NHibernate/Async/Impl/MultiQueryImpl.cs | 1 + .../Async/Loader/Hql/IQueryLoader.cs | 24 ++++ .../Async/Loader/Hql/QueryLoader.cs | 5 +- src/NHibernate/Async/Loader/ILoader.cs | 57 ++++++++ src/NHibernate/Async/Loader/Loader.cs | 22 +-- .../Async/Multi/QueryBatchItemBase.cs | 1 + src/NHibernate/Cache/CachePutData.cs | 2 +- .../Cache/QueryCacheResultBuilder.cs | 5 +- src/NHibernate/Engine/Query/QueryPlanCache.cs | 15 ++- .../Ast/ANTLR/ASTQueryTranslatorFactory.cs | 30 ++++- .../Hql/Ast/ANTLR/QueryTranslatorImpl.cs | 20 ++- src/NHibernate/Hql/IQueryTranslator.cs | 3 +- src/NHibernate/IQueryExpression.cs | 2 +- src/NHibernate/Impl/MultiQueryImpl.cs | 7 +- src/NHibernate/Linq/DefaultQueryProvider.cs | 2 +- src/NHibernate/Linq/ILinqQueryExpression.cs | 12 ++ src/NHibernate/Linq/NhLinqExpression.cs | 8 +- src/NHibernate/Linq/NhLinqExpressionCache.cs | 4 +- .../Loader/Criteria/CriteriaLoader.cs | 2 +- src/NHibernate/Loader/Custom/CustomLoader.cs | 4 +- src/NHibernate/Loader/Hql/IQueryLoader.cs | 12 ++ src/NHibernate/Loader/Hql/QueryLoader.cs | 7 +- src/NHibernate/Loader/ILoader.cs | 125 ++++++++++++++++++ src/NHibernate/Loader/Loader.cs | 43 +++--- src/NHibernate/Multi/QueryBatchItemBase.cs | 8 +- src/NHibernate/NHibernate.csproj | 1 + src/NHibernate/Persister/IPersister.cs | 2 +- 33 files changed, 404 insertions(+), 79 deletions(-) create mode 100644 src/NHibernate/Async/Loader/Hql/IQueryLoader.cs create mode 100644 src/NHibernate/Async/Loader/ILoader.cs create mode 100644 src/NHibernate/Linq/ILinqQueryExpression.cs create mode 100644 src/NHibernate/Loader/Hql/IQueryLoader.cs create mode 100644 src/NHibernate/Loader/ILoader.cs diff --git a/build-common/NHibernate.props b/build-common/NHibernate.props index 5e27ab81d28..ce7a53ef53a 100644 --- a/build-common/NHibernate.props +++ b/build-common/NHibernate.props @@ -3,7 +3,7 @@ 5.4 - 0 + 1 9.0 diff --git a/src/NHibernate.Test/BulkManipulation/BaseFixture.cs b/src/NHibernate.Test/BulkManipulation/BaseFixture.cs index 964e71dfb64..375870fa6c9 100644 --- a/src/NHibernate.Test/BulkManipulation/BaseFixture.cs +++ b/src/NHibernate.Test/BulkManipulation/BaseFixture.cs @@ -2,6 +2,9 @@ using System.Collections; using NHibernate.Hql.Ast.ANTLR; using System.Collections.Generic; +using NHibernate.Engine; +using NHibernate.Hql.Ast.ANTLR.Tree; +using NHibernate.Loader.Hql; using NHibernate.Util; namespace NHibernate.Test.BulkManipulation @@ -34,9 +37,22 @@ protected override void Configure(Cfg.Configuration configuration) public string GetSql(string query) { - var qt = new QueryTranslatorImpl(null, new HqlParseEngine(query, false, Sfi).Parse(), emptyfilters, Sfi); + var qt = new QueryTranslatorImpl(null, + new HqlParseEngine(query, false, Sfi).Parse(), + emptyfilters, + Sfi, + CreateQueryLoader); qt.Compile(null, false); return qt.SQLString; } + + private static IQueryLoader CreateQueryLoader(QueryTranslatorImpl queryTranslatorImpl, + ISessionFactoryImplementor sessionFactoryImplementor, + SelectClause selectClause) + { + return new QueryLoader(queryTranslatorImpl, + sessionFactoryImplementor, + selectClause); + } } } diff --git a/src/NHibernate.Test/Hql/Ast/BaseFixture.cs b/src/NHibernate.Test/Hql/Ast/BaseFixture.cs index cd12d32802b..eeeb6299e99 100644 --- a/src/NHibernate.Test/Hql/Ast/BaseFixture.cs +++ b/src/NHibernate.Test/Hql/Ast/BaseFixture.cs @@ -1,7 +1,10 @@ using System; using System.Collections; using System.Collections.Generic; +using NHibernate.Engine; using NHibernate.Hql.Ast.ANTLR; +using NHibernate.Hql.Ast.ANTLR.Tree; +using NHibernate.Loader.Hql; using NHibernate.Util; namespace NHibernate.Test.Hql.Ast @@ -39,9 +42,22 @@ public string GetSql(string query) public string GetSql(string query, IDictionary replacements) { - var qt = new QueryTranslatorImpl(null, new HqlParseEngine(query, false, Sfi).Parse(), emptyfilters, Sfi); + var qt = new QueryTranslatorImpl(null, + new HqlParseEngine(query, false, Sfi).Parse(), + emptyfilters, + Sfi, + CreateQueryLoader); qt.Compile(replacements, false); return qt.SQLString; } + + private static IQueryLoader CreateQueryLoader(QueryTranslatorImpl queryTranslatorImpl, + ISessionFactoryImplementor sessionFactoryImplementor, + SelectClause selectClause) + { + return new QueryLoader(queryTranslatorImpl, + sessionFactoryImplementor, + selectClause); + } } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH2031/HqlModFuctionForMsSqlTest.cs b/src/NHibernate.Test/NHSpecificTest/NH2031/HqlModFuctionForMsSqlTest.cs index 93f45581b30..37e60c833a6 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2031/HqlModFuctionForMsSqlTest.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2031/HqlModFuctionForMsSqlTest.cs @@ -1,5 +1,8 @@ using NHibernate.Dialect; +using NHibernate.Engine; using NHibernate.Hql.Ast.ANTLR; +using NHibernate.Hql.Ast.ANTLR.Tree; +using NHibernate.Loader.Hql; using NHibernate.Util; using NUnit.Framework; @@ -27,9 +30,22 @@ public void TheModuleOperationShouldAddParenthesisToAvoidWrongSentence() public string GetSql(string query) { - var qt = new QueryTranslatorImpl(null, new HqlParseEngine(query, false, Sfi).Parse(), CollectionHelper.EmptyDictionary(), Sfi); + var qt = new QueryTranslatorImpl(null, + new HqlParseEngine(query, false, Sfi).Parse(), + CollectionHelper.EmptyDictionary(), + Sfi, + CreateQueryLoader); qt.Compile(null, false); return qt.SQLString; } + + private static IQueryLoader CreateQueryLoader(QueryTranslatorImpl queryTranslatorImpl, + ISessionFactoryImplementor sessionFactoryImplementor, + SelectClause selectClause) + { + return new QueryLoader(queryTranslatorImpl, + sessionFactoryImplementor, + selectClause); + } } } diff --git a/src/NHibernate/Async/Hql/Ast/ANTLR/QueryTranslatorImpl.cs b/src/NHibernate/Async/Hql/Ast/ANTLR/QueryTranslatorImpl.cs index 9a34ba265f4..662e36424aa 100644 --- a/src/NHibernate/Async/Hql/Ast/ANTLR/QueryTranslatorImpl.cs +++ b/src/NHibernate/Async/Hql/Ast/ANTLR/QueryTranslatorImpl.cs @@ -14,13 +14,13 @@ using System.Linq; using Antlr.Runtime; using Antlr.Runtime.Tree; - using NHibernate.Engine; using NHibernate.Engine.Query; using NHibernate.Event; using NHibernate.Hql.Ast.ANTLR.Exec; using NHibernate.Hql.Ast.ANTLR.Tree; using NHibernate.Hql.Ast.ANTLR.Util; +using NHibernate.Loader; using NHibernate.Loader.Hql; using NHibernate.Param; using NHibernate.Persister; diff --git a/src/NHibernate/Async/Hql/IQueryTranslator.cs b/src/NHibernate/Async/Hql/IQueryTranslator.cs index fd11e81d03b..dc20147ba64 100644 --- a/src/NHibernate/Async/Hql/IQueryTranslator.cs +++ b/src/NHibernate/Async/Hql/IQueryTranslator.cs @@ -13,6 +13,7 @@ using NHibernate.Engine; using NHibernate.Engine.Query; using NHibernate.Event; +using NHibernate.Loader; using NHibernate.Type; namespace NHibernate.Hql diff --git a/src/NHibernate/Async/Impl/MultiQueryImpl.cs b/src/NHibernate/Async/Impl/MultiQueryImpl.cs index 166588a7bc3..3ecc5e5b933 100644 --- a/src/NHibernate/Async/Impl/MultiQueryImpl.cs +++ b/src/NHibernate/Async/Impl/MultiQueryImpl.cs @@ -19,6 +19,7 @@ using NHibernate.Engine.Query.Sql; using NHibernate.Exceptions; using NHibernate.Hql; +using NHibernate.Loader; using NHibernate.Loader.Custom; using NHibernate.Loader.Custom.Sql; using NHibernate.SqlCommand; diff --git a/src/NHibernate/Async/Loader/Hql/IQueryLoader.cs b/src/NHibernate/Async/Loader/Hql/IQueryLoader.cs new file mode 100644 index 00000000000..cd3e18ab518 --- /dev/null +++ b/src/NHibernate/Async/Loader/Hql/IQueryLoader.cs @@ -0,0 +1,24 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System.Collections; +using NHibernate.Engine; +using NHibernate.Event; + +namespace NHibernate.Loader.Hql +{ + using System.Threading.Tasks; + using System.Threading; + public partial interface IQueryLoader: ILoader + { + Task ListAsync(ISessionImplementor session, QueryParameters queryParameters, CancellationToken cancellationToken); + Task GetEnumerableAsync(QueryParameters queryParameters, IEventSource session, CancellationToken cancellationToken); + } +} diff --git a/src/NHibernate/Async/Loader/Hql/QueryLoader.cs b/src/NHibernate/Async/Loader/Hql/QueryLoader.cs index 83832ddf38b..8f69a6ffbb1 100644 --- a/src/NHibernate/Async/Loader/Hql/QueryLoader.cs +++ b/src/NHibernate/Async/Loader/Hql/QueryLoader.cs @@ -13,7 +13,6 @@ using System.Collections.Generic; using System.Data.Common; using System.Diagnostics; -using System.Linq; using NHibernate.Engine; using NHibernate.Event; using NHibernate.Hql.Ast.ANTLR; @@ -32,7 +31,7 @@ namespace NHibernate.Loader.Hql { using System.Threading.Tasks; using System.Threading; - public partial class QueryLoader : BasicLoader + public partial class QueryLoader : BasicLoader, IQueryLoader { public Task ListAsync(ISessionImplementor session, QueryParameters queryParameters, CancellationToken cancellationToken) @@ -89,7 +88,7 @@ protected override async Task GetResultRowAsync(object[] row, DbDataRe return resultRow; } - internal async Task GetEnumerableAsync(QueryParameters queryParameters, IEventSource session, CancellationToken cancellationToken) + public async Task GetEnumerableAsync(QueryParameters queryParameters, IEventSource session, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); CheckQuery(queryParameters); diff --git a/src/NHibernate/Async/Loader/ILoader.cs b/src/NHibernate/Async/Loader/ILoader.cs new file mode 100644 index 00000000000..1f0d6824b02 --- /dev/null +++ b/src/NHibernate/Async/Loader/ILoader.cs @@ -0,0 +1,57 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data.Common; +using NHibernate.Cache; +using NHibernate.Engine; +using NHibernate.Persister; +using NHibernate.Persister.Entity; +using NHibernate.SqlCommand; +using NHibernate.Transform; +using NHibernate.Type; + +namespace NHibernate.Loader +{ + using System.Threading.Tasks; + using System.Threading; + public partial interface ILoader + { + + Task GetRowFromResultSetAsync(DbDataReader resultSet, ISessionImplementor session, + QueryParameters queryParameters, LockMode[] lockModeArray, + EntityKey optionalObjectKey, IList hydratedObjects, EntityKey[] keys, + bool returnProxies, IResultTransformer forcedResultTransformer, + QueryCacheResultBuilder queryCacheResultBuilder, + Action cacheBatchingHandler, CancellationToken cancellationToken); + + Task InitializeEntitiesAndCollectionsAsync(IList hydratedObjects, + DbDataReader reader, + ISessionImplementor session, + bool readOnly, + CacheBatcher cacheBatcher, CancellationToken cancellationToken); + + /// + /// Called by subclasses that load collections + /// + Task LoadCollectionAsync(ISessionImplementor session, + object id, + IType type, CancellationToken cancellationToken); + + /// + /// Called by wrappers that batch initialize collections + /// + Task LoadCollectionBatchAsync(ISessionImplementor session, + object[] ids, + IType type, CancellationToken cancellationToken); + } +} diff --git a/src/NHibernate/Async/Loader/Loader.cs b/src/NHibernate/Async/Loader/Loader.cs index 128130c5b74..4424f3cb9d4 100644 --- a/src/NHibernate/Async/Loader/Loader.cs +++ b/src/NHibernate/Async/Loader/Loader.cs @@ -41,7 +41,7 @@ namespace NHibernate.Loader { using System.Threading.Tasks; using System.Threading; - public abstract partial class Loader + public abstract partial class Loader : ILoader { /// @@ -141,12 +141,12 @@ protected async Task LoadSingleRowAsync(DbDataReader resultSet, ISession return result; } - internal async Task GetRowFromResultSetAsync(DbDataReader resultSet, ISessionImplementor session, - QueryParameters queryParameters, LockMode[] lockModeArray, - EntityKey optionalObjectKey, IList hydratedObjects, EntityKey[] keys, - bool returnProxies, IResultTransformer forcedResultTransformer, - QueryCacheResultBuilder queryCacheResultBuilder, - Action cacheBatchingHandler, CancellationToken cancellationToken) + public async Task GetRowFromResultSetAsync(DbDataReader resultSet, ISessionImplementor session, + QueryParameters queryParameters, LockMode[] lockModeArray, + EntityKey optionalObjectKey, IList hydratedObjects, EntityKey[] keys, + bool returnProxies, IResultTransformer forcedResultTransformer, + QueryCacheResultBuilder queryCacheResultBuilder, + Action cacheBatchingHandler, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ILoadable[] persisters = EntityPersisters; @@ -341,9 +341,11 @@ private async Task DoQueryAsync(ISessionImplementor session, QueryParamet } } - internal async Task InitializeEntitiesAndCollectionsAsync( - IList hydratedObjects, DbDataReader reader, ISessionImplementor session, bool readOnly, - CacheBatcher cacheBatcher, CancellationToken cancellationToken) + public async Task InitializeEntitiesAndCollectionsAsync(IList hydratedObjects, + DbDataReader reader, + ISessionImplementor session, + bool readOnly, + CacheBatcher cacheBatcher, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ICollectionPersister[] collectionPersisters = CollectionPersisters; diff --git a/src/NHibernate/Async/Multi/QueryBatchItemBase.cs b/src/NHibernate/Async/Multi/QueryBatchItemBase.cs index e590cc77f6f..f596da92f44 100644 --- a/src/NHibernate/Async/Multi/QueryBatchItemBase.cs +++ b/src/NHibernate/Async/Multi/QueryBatchItemBase.cs @@ -15,6 +15,7 @@ using System.Linq; using NHibernate.Cache; using NHibernate.Engine; +using NHibernate.Loader; using NHibernate.SqlCommand; using NHibernate.Type; using NHibernate.Util; diff --git a/src/NHibernate/Cache/CachePutData.cs b/src/NHibernate/Cache/CachePutData.cs index 463a3405862..ba1bfa2998d 100644 --- a/src/NHibernate/Cache/CachePutData.cs +++ b/src/NHibernate/Cache/CachePutData.cs @@ -10,7 +10,7 @@ namespace NHibernate.Cache /// /// The data used to put a value to the 2nd level cache. /// - internal class CachePutData + public class CachePutData { public CachePutData(CacheKey key, object value, object version, IComparer versionComparer, bool minimalPut) { diff --git a/src/NHibernate/Cache/QueryCacheResultBuilder.cs b/src/NHibernate/Cache/QueryCacheResultBuilder.cs index fff6fe08d75..fe29badf5cf 100644 --- a/src/NHibernate/Cache/QueryCacheResultBuilder.cs +++ b/src/NHibernate/Cache/QueryCacheResultBuilder.cs @@ -2,6 +2,7 @@ using System.Collections; using System.Collections.Generic; using NHibernate.Collection; +using NHibernate.Loader; using NHibernate.Type; namespace NHibernate.Cache @@ -14,12 +15,12 @@ public sealed class QueryCacheResultBuilder private readonly IType[] _resultTypes; private readonly Loader.Loader.QueryCacheInfo _cacheInfo; - public static bool IsCacheWithFetches(Loader.Loader loader) + public static bool IsCacheWithFetches(ILoader loader) { return loader.CacheTypes.Length > loader.ResultTypes.Length; } - internal QueryCacheResultBuilder(Loader.Loader loader) + internal QueryCacheResultBuilder(ILoader loader) { _resultTypes = loader.ResultTypes; diff --git a/src/NHibernate/Engine/Query/QueryPlanCache.cs b/src/NHibernate/Engine/Query/QueryPlanCache.cs index d6d13243512..424d4f38b6a 100644 --- a/src/NHibernate/Engine/Query/QueryPlanCache.cs +++ b/src/NHibernate/Engine/Query/QueryPlanCache.cs @@ -69,10 +69,14 @@ public IQueryExpressionPlan GetHQLQueryPlan(IQueryExpression queryExpression, bo plan = new QueryExpressionPlan(queryExpression, shallow, enabledFilters, factory); // 6.0 TODO: add "CanCachePlan { get; }" to IQueryExpression interface - if (!(queryExpression is ICacheableQueryExpression linqExpression) || linqExpression.CanCachePlan) + if(queryExpression is ICacheableQueryExpression linqExpression && linqExpression.CanCachePlan) + { planCache.Put(key, PreparePlanToCache(plan)); + } else + { log.Debug("Query plan not cacheable"); + } } else { @@ -88,7 +92,7 @@ public IQueryExpressionPlan GetHQLQueryPlan(IQueryExpression queryExpression, bo private QueryExpressionPlan PreparePlanToCache(QueryExpressionPlan plan) { - if (plan.QueryExpression is NhLinqExpression planExpression) + if (plan.QueryExpression is ILinqQueryExpression planExpression) { return plan.Copy(new NhLinqExpressionCache(planExpression)); } @@ -98,7 +102,8 @@ private QueryExpressionPlan PreparePlanToCache(QueryExpressionPlan plan) private static QueryExpressionPlan CopyIfRequired(QueryExpressionPlan plan, IQueryExpression queryExpression) { - if (plan.QueryExpression is NhLinqExpressionCache cache && queryExpression is NhLinqExpression expression) + if (plan.QueryExpression is NhLinqExpressionCache cache && + queryExpression is ILinqQueryExpression linqExpression) { //NH-3413 //Here we have to use original expression. @@ -109,8 +114,8 @@ private static QueryExpressionPlan CopyIfRequired(QueryExpressionPlan plan, IQue //NH-3436 // We have to return new instance plan with it's own query expression // because other treads can override query expression of current plan during execution of query if we will use cached instance of plan - expression.CopyExpressionTranslation(cache); - plan = plan.Copy(expression); + linqExpression.CopyExpressionTranslation(cache); + plan = plan.Copy(linqExpression); } return plan; diff --git a/src/NHibernate/Hql/Ast/ANTLR/ASTQueryTranslatorFactory.cs b/src/NHibernate/Hql/Ast/ANTLR/ASTQueryTranslatorFactory.cs index 66fa4ecf5af..41134d22f5a 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/ASTQueryTranslatorFactory.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/ASTQueryTranslatorFactory.cs @@ -2,6 +2,7 @@ using NHibernate.Engine; using NHibernate.Hql.Ast.ANTLR.Tree; using NHibernate.Linq; +using NHibernate.Loader.Hql; using NHibernate.Util; namespace NHibernate.Hql.Ast.ANTLR @@ -33,8 +34,17 @@ static IQueryTranslator[] CreateQueryTranslators( var translators = polymorphicParsers .ToArray(hql => queryExpression is NhLinqExpression linqExpression - ? new QueryTranslatorImpl(queryIdentifier, hql, filters, factory, linqExpression.GetNamedParameterTypes()) - : new QueryTranslatorImpl(queryIdentifier, hql, filters, factory)); + ? new QueryTranslatorImpl(queryIdentifier, + hql, + filters, + factory, + CreateQueryLoader, + linqExpression.GetNamedParameterTypes()) + : new QueryTranslatorImpl(queryIdentifier, + hql, + filters, + factory, + CreateQueryLoader)); foreach (var translator in translators) { @@ -50,5 +60,21 @@ static IQueryTranslator[] CreateQueryTranslators( return translators; } + + /// + /// Creates a query loader. + /// + /// + /// + /// + /// + private static IQueryLoader CreateQueryLoader(QueryTranslatorImpl queryTranslatorImpl, + ISessionFactoryImplementor sessionFactoryImplementor, + SelectClause selectClause) + { + return new QueryLoader(queryTranslatorImpl, + sessionFactoryImplementor, + selectClause); + } } } diff --git a/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs b/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs index a30e5594c29..d1b38966a10 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs @@ -4,13 +4,13 @@ using System.Linq; using Antlr.Runtime; using Antlr.Runtime.Tree; - using NHibernate.Engine; using NHibernate.Engine.Query; using NHibernate.Event; using NHibernate.Hql.Ast.ANTLR.Exec; using NHibernate.Hql.Ast.ANTLR.Tree; using NHibernate.Hql.Ast.ANTLR.Util; +using NHibernate.Loader; using NHibernate.Loader.Hql; using NHibernate.Param; using NHibernate.Persister; @@ -30,12 +30,13 @@ public partial class QueryTranslatorImpl : IFilterTranslator private readonly string _queryIdentifier; private readonly IASTNode _stageOneAst; private readonly ISessionFactoryImplementor _factory; + private readonly Func _queryLoaderFactory; private readonly IDictionary> _namedParameters; private bool _shallowQuery; private bool _compiled; private IDictionary _enabledFilters; - private QueryLoader _queryLoader; + private IQueryLoader _queryLoader; private IStatementExecutor _statementExecutor; private IStatement _sqlAst; private IDictionary _tokenReplacements; @@ -48,12 +49,14 @@ public partial class QueryTranslatorImpl : IFilterTranslator /// The hql query to translate /// Currently enabled filters /// The session factory constructing this translator instance. + /// A query loader factory method. public QueryTranslatorImpl( string queryIdentifier, IASTNode parsedQuery, IDictionary enabledFilters, - ISessionFactoryImplementor factory) - : this(queryIdentifier, parsedQuery, enabledFilters, factory, null) + ISessionFactoryImplementor factory, + Func queryLoaderFactory) + : this(queryIdentifier, parsedQuery, enabledFilters, factory, queryLoaderFactory, null) { } @@ -64,12 +67,14 @@ public QueryTranslatorImpl( /// The hql query to translate /// Currently enabled filters /// The session factory constructing this translator instance. + /// A query loader factory method. /// The named parameters information. - internal QueryTranslatorImpl( + public QueryTranslatorImpl( string queryIdentifier, IASTNode parsedQuery, IDictionary enabledFilters, ISessionFactoryImplementor factory, + Func queryLoaderFactory, IDictionary> namedParameters) { _queryIdentifier = queryIdentifier; @@ -78,6 +83,7 @@ internal QueryTranslatorImpl( _shallowQuery = false; _enabledFilters = enabledFilters; _factory = factory; + _queryLoaderFactory = queryLoaderFactory; _namedParameters = namedParameters; } @@ -192,7 +198,7 @@ private void ErrorIfSelect() } } - public NHibernate.Loader.Loader Loader + public ILoader Loader { get { return _queryLoader; } } @@ -393,7 +399,7 @@ private void DoCompile(IDictionary replacements, bool shallow, S _generator = new HqlSqlGenerator(_sqlAst, _factory); _generator.Generate(); - _queryLoader = new QueryLoader(this, _factory, _sqlAst.Walker.SelectClause); + _queryLoader = _queryLoaderFactory(this, _factory, _sqlAst.Walker.SelectClause); } _compiled = true; diff --git a/src/NHibernate/Hql/IQueryTranslator.cs b/src/NHibernate/Hql/IQueryTranslator.cs index b74bcfd2f8e..7352de70469 100644 --- a/src/NHibernate/Hql/IQueryTranslator.cs +++ b/src/NHibernate/Hql/IQueryTranslator.cs @@ -3,6 +3,7 @@ using NHibernate.Engine; using NHibernate.Engine.Query; using NHibernate.Event; +using NHibernate.Loader; using NHibernate.Type; namespace NHibernate.Hql @@ -113,7 +114,7 @@ public partial interface IQueryTranslator bool IsManipulationStatement { get; } - Loader.Loader Loader { get; } + ILoader Loader { get; } IType[] ActualReturnTypes { get; } diff --git a/src/NHibernate/IQueryExpression.cs b/src/NHibernate/IQueryExpression.cs index 65bbe121f68..93234677800 100755 --- a/src/NHibernate/IQueryExpression.cs +++ b/src/NHibernate/IQueryExpression.cs @@ -6,7 +6,7 @@ namespace NHibernate { //TODO 6.0: Merge into IQueryExpression - internal interface ICacheableQueryExpression + public interface ICacheableQueryExpression { bool CanCachePlan { get; } } diff --git a/src/NHibernate/Impl/MultiQueryImpl.cs b/src/NHibernate/Impl/MultiQueryImpl.cs index 120632ab7b1..a8b15eb8df1 100644 --- a/src/NHibernate/Impl/MultiQueryImpl.cs +++ b/src/NHibernate/Impl/MultiQueryImpl.cs @@ -9,6 +9,7 @@ using NHibernate.Engine.Query.Sql; using NHibernate.Exceptions; using NHibernate.Hql; +using NHibernate.Loader; using NHibernate.Loader.Custom; using NHibernate.Loader.Custom.Sql; using NHibernate.SqlCommand; @@ -802,7 +803,7 @@ private int AddQueryForLaterExecutionAndReturnIndexOfQuery(System.Type resultGen public interface ITranslator { - Loader.Loader Loader { get; } + ILoader Loader { get; } IType[] ReturnTypes { get; } string[] ReturnAliases { get; } ICollection QuerySpaces { get; } @@ -817,7 +818,7 @@ public HqlTranslatorWrapper(IQueryTranslator translator) innerTranslator = translator; } - public Loader.Loader Loader + public ILoader Loader { get { return innerTranslator.Loader; } } @@ -855,7 +856,7 @@ public IType[] ReturnTypes get { return loader.ResultTypes; } } - public Loader.Loader Loader + public ILoader Loader { get { return loader; } } diff --git a/src/NHibernate/Linq/DefaultQueryProvider.cs b/src/NHibernate/Linq/DefaultQueryProvider.cs index cb1e84c41a6..e90b02c29dd 100644 --- a/src/NHibernate/Linq/DefaultQueryProvider.cs +++ b/src/NHibernate/Linq/DefaultQueryProvider.cs @@ -253,7 +253,7 @@ protected virtual object ExecuteQuery(NhLinqExpression nhLinqExpression, IQuery #pragma warning restore 618 } - private static void SetParameters(IQuery query, IDictionary parameters) + protected void SetParameters(IQuery query, IDictionary parameters) { foreach (var parameterName in query.NamedParameters) { diff --git a/src/NHibernate/Linq/ILinqQueryExpression.cs b/src/NHibernate/Linq/ILinqQueryExpression.cs new file mode 100644 index 00000000000..956b506fbbd --- /dev/null +++ b/src/NHibernate/Linq/ILinqQueryExpression.cs @@ -0,0 +1,12 @@ +namespace NHibernate.Linq +{ + /// + /// Defines a linq query expression. + /// + public interface ILinqQueryExpression: IQueryExpression, ICacheableQueryExpression + { + ExpressionToHqlTranslationResults ExpressionToHqlTranslationResults { get; } + + void CopyExpressionTranslation(NhLinqExpressionCache cache); + } +} diff --git a/src/NHibernate/Linq/NhLinqExpression.cs b/src/NHibernate/Linq/NhLinqExpression.cs index 04f4d864ea4..7ca17a4549c 100644 --- a/src/NHibernate/Linq/NhLinqExpression.cs +++ b/src/NHibernate/Linq/NhLinqExpression.cs @@ -11,7 +11,7 @@ namespace NHibernate.Linq { - public class NhLinqExpression : IQueryExpression, ICacheableQueryExpression + public class NhLinqExpression : ILinqQueryExpression { public string Key { get; protected set; } @@ -34,7 +34,7 @@ public class NhLinqExpression : IQueryExpression, ICacheableQueryExpression protected virtual QueryMode QueryMode { get; } - internal IDictionary NamedParameters { get; } + public IDictionary NamedParameters { get; } private readonly Expression _expression; private readonly IDictionary _constantToParameterMap; @@ -113,7 +113,7 @@ public IASTNode Translate(ISessionFactoryImplementor sessionFactory, bool filter return DuplicateTree(ExpressionToHqlTranslationResults.Statement.AstNode); } - internal void CopyExpressionTranslation(NhLinqExpressionCache cache) + public void CopyExpressionTranslation(NhLinqExpressionCache cache) { ExpressionToHqlTranslationResults = cache.ExpressionToHqlTranslationResults; ParameterDescriptors = cache.ParameterDescriptors; @@ -121,7 +121,7 @@ internal void CopyExpressionTranslation(NhLinqExpressionCache cache) Type = cache.Type; } - internal IDictionary> GetNamedParameterTypes() + public IDictionary> GetNamedParameterTypes() { return _constantToParameterMap.Values.Distinct() .ToDictionary(p => p.Name, p => System.Tuple.Create(p.Type, p.IsGuessedType)); diff --git a/src/NHibernate/Linq/NhLinqExpressionCache.cs b/src/NHibernate/Linq/NhLinqExpressionCache.cs index 5ffa587252a..97d884e7fef 100644 --- a/src/NHibernate/Linq/NhLinqExpressionCache.cs +++ b/src/NHibernate/Linq/NhLinqExpressionCache.cs @@ -6,9 +6,9 @@ namespace NHibernate.Linq { - internal class NhLinqExpressionCache : IQueryExpression + public class NhLinqExpressionCache : IQueryExpression { - internal NhLinqExpressionCache(NhLinqExpression expression) + internal NhLinqExpressionCache(ILinqQueryExpression expression) { ExpressionToHqlTranslationResults = expression.ExpressionToHqlTranslationResults ?? throw new ArgumentException("NhLinqExpression is not translated"); Key = expression.Key; diff --git a/src/NHibernate/Loader/Criteria/CriteriaLoader.cs b/src/NHibernate/Loader/Criteria/CriteriaLoader.cs index 091209372ab..b4f16d2672a 100644 --- a/src/NHibernate/Loader/Criteria/CriteriaLoader.cs +++ b/src/NHibernate/Loader/Criteria/CriteriaLoader.cs @@ -98,7 +98,7 @@ public ISet QuerySpaces get { return querySpaces; } } - internal override bool IsCacheable(QueryParameters queryParameters) + public override bool IsCacheable(QueryParameters queryParameters) { return IsCacheable(queryParameters, translator.SupportsQueryCache, translator.GetPersisters()); } diff --git a/src/NHibernate/Loader/Custom/CustomLoader.cs b/src/NHibernate/Loader/Custom/CustomLoader.cs index 5427d153523..fb5606a283d 100644 --- a/src/NHibernate/Loader/Custom/CustomLoader.cs +++ b/src/NHibernate/Loader/Custom/CustomLoader.cs @@ -207,7 +207,7 @@ public ISet QuerySpaces get { return querySpaces; } } - internal override bool IsCacheable(QueryParameters queryParameters) + public override bool IsCacheable(QueryParameters queryParameters) { return IsCacheable( queryParameters, @@ -359,7 +359,7 @@ public override IList GetResultList(IList results, IResultTransformer resultTran return results; } - protected internal override void AutoDiscoverTypes( + public override void AutoDiscoverTypes( DbDataReader rs, QueryParameters queryParameters, IResultTransformer forcedResultTransformer) { MetaData metadata = new MetaData(rs); diff --git a/src/NHibernate/Loader/Hql/IQueryLoader.cs b/src/NHibernate/Loader/Hql/IQueryLoader.cs new file mode 100644 index 00000000000..25de6138578 --- /dev/null +++ b/src/NHibernate/Loader/Hql/IQueryLoader.cs @@ -0,0 +1,12 @@ +using System.Collections; +using NHibernate.Engine; +using NHibernate.Event; + +namespace NHibernate.Loader.Hql +{ + public partial interface IQueryLoader: ILoader + { + IList List(ISessionImplementor session, QueryParameters queryParameters); + IEnumerable GetEnumerable(QueryParameters queryParameters, IEventSource session); + } +} diff --git a/src/NHibernate/Loader/Hql/QueryLoader.cs b/src/NHibernate/Loader/Hql/QueryLoader.cs index 03617aa8887..c1209626ac3 100644 --- a/src/NHibernate/Loader/Hql/QueryLoader.cs +++ b/src/NHibernate/Loader/Hql/QueryLoader.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Data.Common; using System.Diagnostics; -using System.Linq; using NHibernate.Engine; using NHibernate.Event; using NHibernate.Hql.Ast.ANTLR; @@ -21,7 +20,7 @@ namespace NHibernate.Loader.Hql { [CLSCompliant(false)] - public partial class QueryLoader : BasicLoader + public partial class QueryLoader : BasicLoader, IQueryLoader { private readonly QueryTranslatorImpl _queryTranslator; @@ -109,7 +108,7 @@ protected override string[] Aliases get { return _sqlAliases; } } - internal override bool IsCacheable(QueryParameters queryParameters) + public override bool IsCacheable(QueryParameters queryParameters) { return IsCacheable(queryParameters, _queryTranslator.SupportsQueryCache, _queryTranslator.Persisters); } @@ -430,7 +429,7 @@ protected override bool[] IncludeInResultRow [Obsolete("Please use ResultTypes instead")] public IType[] ReturnTypes => ResultTypes; - internal IEnumerable GetEnumerable(QueryParameters queryParameters, IEventSource session) + public IEnumerable GetEnumerable(QueryParameters queryParameters, IEventSource session) { CheckQuery(queryParameters); Stopwatch stopWatch = null; diff --git a/src/NHibernate/Loader/ILoader.cs b/src/NHibernate/Loader/ILoader.cs new file mode 100644 index 00000000000..b5084a751fd --- /dev/null +++ b/src/NHibernate/Loader/ILoader.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data.Common; +using NHibernate.Cache; +using NHibernate.Engine; +using NHibernate.Persister; +using NHibernate.Persister.Entity; +using NHibernate.SqlCommand; +using NHibernate.Transform; +using NHibernate.Type; + +namespace NHibernate.Loader +{ + public partial interface ILoader + { + bool IsSubselectLoadingEnabled { get; } + + /// + /// The result types of the result set, for query loaders. + /// + IType[] ResultTypes { get; } + + IType[] CacheTypes { get; } + Loader.QueryCacheInfo CacheInfo { get; } + ISessionFactoryImplementor Factory { get; } + + /// + /// The SqlString to be called; implemented by all subclasses + /// + SqlString SqlString { get; } + + /// + /// An array of persisters of entity classes contained in each row of results; + /// implemented by all subclasses + /// + /// + /// The setter was added so that classes inheriting from Loader could write a + /// value using the Property instead of directly to the field. + /// + ILoadable[] EntityPersisters { get; } + + /// + /// Identifies the query for statistics reporting, if null, + /// no statistics will be reported + /// + string QueryIdentifier { get; } + + /// + /// What lock mode does this load entities with? + /// + /// A Collection of lock modes specified dynamically via the Query Interface + /// + LockMode[] GetLockModes(IDictionary lockModes); + + object GetRowFromResultSet(DbDataReader resultSet, ISessionImplementor session, + QueryParameters queryParameters, LockMode[] lockModeArray, + EntityKey optionalObjectKey, IList hydratedObjects, EntityKey[] keys, + bool returnProxies, IResultTransformer forcedResultTransformer, + QueryCacheResultBuilder queryCacheResultBuilder, + Action cacheBatchingHandler); + + void CreateSubselects(List keys, QueryParameters queryParameters, ISessionImplementor session); + + void InitializeEntitiesAndCollections(IList hydratedObjects, + DbDataReader reader, + ISessionImplementor session, + bool readOnly, + CacheBatcher cacheBatcher); + + IList GetResultList(IList results, IResultTransformer resultTransformer); + + /// + /// Should we pre-process the SQL string, adding a dialect-specific + /// LIMIT clause. + /// + /// + /// + /// + bool UseLimit(RowSelection selection, Dialect.Dialect dialect); + + /// + /// Called by subclasses that load collections + /// + void LoadCollection(ISessionImplementor session, + object id, + IType type); + + /// + /// Called by wrappers that batch initialize collections + /// + void LoadCollectionBatch(ISessionImplementor session, + object[] ids, + IType type); + + bool IsCacheable(QueryParameters queryParameters); + + bool IsCacheable(QueryParameters queryParameters, + bool supportsQueryCache, + IEnumerable persisters); + + string ToString(); + + ISqlCommand CreateSqlCommand(QueryParameters queryParameters, + ISessionImplementor session); + + void AutoDiscoverTypes(DbDataReader rs, + QueryParameters queryParameters, + IResultTransformer forcedResultTransformer); + + IList TransformCacheableResults(QueryParameters queryParameters, + CacheableResultTransformer transformer, + IList result); + + void HandleEmptyCollections(object[] keys, + object resultSetId, + ISessionImplementor session); + + void StopLoadingCollections(ISessionImplementor session, + DbDataReader reader); + + QueryKey GenerateQueryKey(ISessionImplementor session, + QueryParameters queryParameters); + } +} diff --git a/src/NHibernate/Loader/Loader.cs b/src/NHibernate/Loader/Loader.cs index 6a74b42032b..6f624400a02 100644 --- a/src/NHibernate/Loader/Loader.cs +++ b/src/NHibernate/Loader/Loader.cs @@ -50,7 +50,7 @@ namespace NHibernate.Loader /// /// /// - public abstract partial class Loader + public abstract partial class Loader : ILoader { /// /// DTO for providing all query cache related details @@ -379,12 +379,12 @@ internal static EntityKey GetOptionalObjectKey(QueryParameters queryParameters, } } - internal object GetRowFromResultSet(DbDataReader resultSet, ISessionImplementor session, - QueryParameters queryParameters, LockMode[] lockModeArray, - EntityKey optionalObjectKey, IList hydratedObjects, EntityKey[] keys, - bool returnProxies, IResultTransformer forcedResultTransformer, - QueryCacheResultBuilder queryCacheResultBuilder, - Action cacheBatchingHandler) + public object GetRowFromResultSet(DbDataReader resultSet, ISessionImplementor session, + QueryParameters queryParameters, LockMode[] lockModeArray, + EntityKey optionalObjectKey, IList hydratedObjects, EntityKey[] keys, + bool returnProxies, IResultTransformer forcedResultTransformer, + QueryCacheResultBuilder queryCacheResultBuilder, + Action cacheBatchingHandler) { ILoadable[] persisters = EntityPersisters; int entitySpan = persisters.Length; @@ -606,7 +606,7 @@ private static ISet[] Transpose(List keys) return result; } - internal void CreateSubselects(List keys, QueryParameters queryParameters, ISessionImplementor session) + public void CreateSubselects(List keys, QueryParameters queryParameters, ISessionImplementor session) { if (keys.Count > 1) { @@ -646,9 +646,11 @@ private IEnumerable CreateSubselects(List keys, Que } } - internal void InitializeEntitiesAndCollections( - IList hydratedObjects, DbDataReader reader, ISessionImplementor session, bool readOnly, - CacheBatcher cacheBatcher) + public void InitializeEntitiesAndCollections(IList hydratedObjects, + DbDataReader reader, + ISessionImplementor session, + bool readOnly, + CacheBatcher cacheBatcher) { ICollectionPersister[] collectionPersisters = CollectionPersisters; var ownCacheBatcher = cacheBatcher == null; @@ -724,7 +726,7 @@ internal void InitializeEntitiesAndCollections( /// /// Stops further collection population without actual collection initialization. /// - internal void StopLoadingCollections(ISessionImplementor session, DbDataReader reader) + public void StopLoadingCollections(ISessionImplementor session, DbDataReader reader) { var collectionPersisters = CollectionPersisters; if (collectionPersisters == null || collectionPersisters.Length == 0) @@ -900,7 +902,7 @@ private static IPersistentCollection ReadCollectionElement(object optionalOwner, /// is being initialized, to account for the possibility of the collection having /// no elements (hence no rows in the result set). /// - internal void HandleEmptyCollections(object[] keys, object resultSetId, ISessionImplementor session) + public void HandleEmptyCollections(object[] keys, object resultSetId, ISessionImplementor session) { if (keys != null) { @@ -1391,7 +1393,7 @@ internal static int GetFirstRow(RowSelection selection) /// /// /// - internal bool UseLimit(RowSelection selection, Dialect.Dialect dialect) + public bool UseLimit(RowSelection selection, Dialect.Dialect dialect) { return (_canUseLimits ?? true) && dialect.SupportsLimit @@ -1563,8 +1565,9 @@ protected internal virtual void AutoDiscoverTypes(DbDataReader rs) AutoDiscoverTypes(rs, new QueryParameters(), null); } - protected internal virtual void AutoDiscoverTypes( - DbDataReader rs, QueryParameters queryParameters, IResultTransformer forcedResultTransformer) + public virtual void AutoDiscoverTypes(DbDataReader rs, + QueryParameters queryParameters, + IResultTransformer forcedResultTransformer) { throw new AssertionFailure("Auto discover types not supported in this loader"); } @@ -1835,12 +1838,12 @@ protected IList List(ISessionImplementor session, QueryParameters queryParameter return ListIgnoreQueryCache(session, queryParameters); } - internal virtual bool IsCacheable(QueryParameters queryParameters) + public virtual bool IsCacheable(QueryParameters queryParameters) { return IsCacheable(queryParameters, true, Enumerable.Empty()); } - internal bool IsCacheable(QueryParameters queryParameters, bool supportsQueryCache, IEnumerable persisters) + public bool IsCacheable(QueryParameters queryParameters, bool supportsQueryCache, IEnumerable persisters) { bool isCacheable = Factory.Settings.IsQueryCacheEnabled && queryParameters.Cacheable; if (isCacheable && !supportsQueryCache) @@ -1892,7 +1895,7 @@ private IList ListUsingQueryCache(ISessionImplementor session, QueryParameters q return GetResultList(result, queryParameters.ResultTransformer); } - internal IList TransformCacheableResults(QueryParameters queryParameters, CacheableResultTransformer transformer, IList result) + public IList TransformCacheableResults(QueryParameters queryParameters, CacheableResultTransformer transformer, IList result) { var resolvedTransformer = ResolveResultTransformer(queryParameters.ResultTransformer); if (resolvedTransformer == null) @@ -1908,7 +1911,7 @@ internal IList TransformCacheableResults(QueryParameters queryParameters, Cachea ); } - internal QueryKey GenerateQueryKey(ISessionImplementor session, QueryParameters queryParameters) + public QueryKey GenerateQueryKey(ISessionImplementor session, QueryParameters queryParameters) { ISet filterKeys = FilterKey.CreateFilterKeys(session.EnabledFilters); return new QueryKey(Factory, SqlString, queryParameters, filterKeys, diff --git a/src/NHibernate/Multi/QueryBatchItemBase.cs b/src/NHibernate/Multi/QueryBatchItemBase.cs index 5a0123650f3..4502757c95f 100644 --- a/src/NHibernate/Multi/QueryBatchItemBase.cs +++ b/src/NHibernate/Multi/QueryBatchItemBase.cs @@ -5,6 +5,7 @@ using System.Linq; using NHibernate.Cache; using NHibernate.Engine; +using NHibernate.Loader; using NHibernate.SqlCommand; using NHibernate.Type; using NHibernate.Util; @@ -31,7 +32,7 @@ protected class QueryInfo : ICachingInformation, ICachingInformationWithFetches /// /// The query loader. /// - public Loader.Loader Loader { get; set; } + public ILoader Loader { get; set; } /// /// The query result. @@ -91,9 +92,8 @@ protected class QueryInfo : ICachingInformation, ICachingInformationWithFetches /// The loader. /// The query spaces. /// The session of the query. - public QueryInfo( - QueryParameters parameters, Loader.Loader loader, ISet querySpaces, - ISessionImplementor session) + public QueryInfo(QueryParameters parameters, ILoader loader, ISet querySpaces, + ISessionImplementor session) { Parameters = parameters; Loader = loader; diff --git a/src/NHibernate/NHibernate.csproj b/src/NHibernate/NHibernate.csproj index 463078ec0dc..1e22abb517c 100644 --- a/src/NHibernate/NHibernate.csproj +++ b/src/NHibernate/NHibernate.csproj @@ -13,6 +13,7 @@ NHibernate is a mature, open source object-relational mapper for the .NET framework. It is actively developed, fully featured and used in thousands of successful projects. ORM; O/RM; DataBase; DAL; ObjectRelationalMapping; NHibernate; ADO.Net; Core NHibernate.readme.md + true diff --git a/src/NHibernate/Persister/IPersister.cs b/src/NHibernate/Persister/IPersister.cs index 6cd5673c2fb..43710dd0f62 100644 --- a/src/NHibernate/Persister/IPersister.cs +++ b/src/NHibernate/Persister/IPersister.cs @@ -5,7 +5,7 @@ namespace NHibernate.Persister { // TODO 6.0: Make this public and make IEntityPersister and ICollectionPersister derive it. - internal interface IPersister + public interface IPersister { /// /// The unique name of the persister. From 69e4da5e54e9150685e9d243a54a31345e69447b Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sun, 11 Dec 2022 23:51:23 +0100 Subject: [PATCH 02/19] NHibernate version changes to build internal custom NuGet package reverted --- build-common/NHibernate.props | 2 +- src/NHibernate/NHibernate.csproj | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/build-common/NHibernate.props b/build-common/NHibernate.props index ce7a53ef53a..5e27ab81d28 100644 --- a/build-common/NHibernate.props +++ b/build-common/NHibernate.props @@ -3,7 +3,7 @@ 5.4 - 1 + 0 9.0 diff --git a/src/NHibernate/NHibernate.csproj b/src/NHibernate/NHibernate.csproj index 1e22abb517c..463078ec0dc 100644 --- a/src/NHibernate/NHibernate.csproj +++ b/src/NHibernate/NHibernate.csproj @@ -13,7 +13,6 @@ NHibernate is a mature, open source object-relational mapper for the .NET framework. It is actively developed, fully featured and used in thousands of successful projects. ORM; O/RM; DataBase; DAL; ObjectRelationalMapping; NHibernate; ADO.Net; Core NHibernate.readme.md - true From a2009d42d8778ffcf270e038fd56daa1760da03d Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Mon, 12 Dec 2022 00:20:08 +0100 Subject: [PATCH 03/19] reverted formatting changes --- src/NHibernate/Engine/Query/QueryPlanCache.cs | 4 --- src/NHibernate/Loader/Loader.cs | 29 ++++++++++--------- src/NHibernate/Multi/QueryBatchItemBase.cs | 5 ++-- 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/src/NHibernate/Engine/Query/QueryPlanCache.cs b/src/NHibernate/Engine/Query/QueryPlanCache.cs index 424d4f38b6a..4ba579c52b3 100644 --- a/src/NHibernate/Engine/Query/QueryPlanCache.cs +++ b/src/NHibernate/Engine/Query/QueryPlanCache.cs @@ -70,13 +70,9 @@ public IQueryExpressionPlan GetHQLQueryPlan(IQueryExpression queryExpression, bo plan = new QueryExpressionPlan(queryExpression, shallow, enabledFilters, factory); // 6.0 TODO: add "CanCachePlan { get; }" to IQueryExpression interface if(queryExpression is ICacheableQueryExpression linqExpression && linqExpression.CanCachePlan) - { planCache.Put(key, PreparePlanToCache(plan)); - } else - { log.Debug("Query plan not cacheable"); - } } else { diff --git a/src/NHibernate/Loader/Loader.cs b/src/NHibernate/Loader/Loader.cs index 6f624400a02..e61557976a9 100644 --- a/src/NHibernate/Loader/Loader.cs +++ b/src/NHibernate/Loader/Loader.cs @@ -379,12 +379,13 @@ internal static EntityKey GetOptionalObjectKey(QueryParameters queryParameters, } } - public object GetRowFromResultSet(DbDataReader resultSet, ISessionImplementor session, - QueryParameters queryParameters, LockMode[] lockModeArray, - EntityKey optionalObjectKey, IList hydratedObjects, EntityKey[] keys, - bool returnProxies, IResultTransformer forcedResultTransformer, - QueryCacheResultBuilder queryCacheResultBuilder, - Action cacheBatchingHandler) + public object GetRowFromResultSet( + DbDataReader resultSet, ISessionImplementor session, + QueryParameters queryParameters, LockMode[] lockModeArray, + EntityKey optionalObjectKey, IList hydratedObjects, EntityKey[] keys, + bool returnProxies, IResultTransformer forcedResultTransformer, + QueryCacheResultBuilder queryCacheResultBuilder, + Action cacheBatchingHandler) { ILoadable[] persisters = EntityPersisters; int entitySpan = persisters.Length; @@ -646,11 +647,12 @@ private IEnumerable CreateSubselects(List keys, Que } } - public void InitializeEntitiesAndCollections(IList hydratedObjects, - DbDataReader reader, - ISessionImplementor session, - bool readOnly, - CacheBatcher cacheBatcher) + public void InitializeEntitiesAndCollections( + IList hydratedObjects, + DbDataReader reader, + ISessionImplementor session, + bool readOnly, + CacheBatcher cacheBatcher) { ICollectionPersister[] collectionPersisters = CollectionPersisters; var ownCacheBatcher = cacheBatcher == null; @@ -1565,9 +1567,8 @@ protected internal virtual void AutoDiscoverTypes(DbDataReader rs) AutoDiscoverTypes(rs, new QueryParameters(), null); } - public virtual void AutoDiscoverTypes(DbDataReader rs, - QueryParameters queryParameters, - IResultTransformer forcedResultTransformer) + public virtual void AutoDiscoverTypes( + DbDataReader rs, QueryParameters queryParameters, IResultTransformer forcedResultTransformer) { throw new AssertionFailure("Auto discover types not supported in this loader"); } diff --git a/src/NHibernate/Multi/QueryBatchItemBase.cs b/src/NHibernate/Multi/QueryBatchItemBase.cs index 4502757c95f..7b7b86338f0 100644 --- a/src/NHibernate/Multi/QueryBatchItemBase.cs +++ b/src/NHibernate/Multi/QueryBatchItemBase.cs @@ -92,8 +92,9 @@ protected class QueryInfo : ICachingInformation, ICachingInformationWithFetches /// The loader. /// The query spaces. /// The session of the query. - public QueryInfo(QueryParameters parameters, ILoader loader, ISet querySpaces, - ISessionImplementor session) + public QueryInfo( + QueryParameters parameters, ILoader loader, ISet querySpaces, + ISessionImplementor session) { Parameters = parameters; Loader = loader; From 4b82fa0c5126fb1b77576db9483a4f9cf4f0c06b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 11 Dec 2022 23:23:22 +0000 Subject: [PATCH 04/19] Generate async files --- src/NHibernate/Async/Loader/Loader.cs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/NHibernate/Async/Loader/Loader.cs b/src/NHibernate/Async/Loader/Loader.cs index 4424f3cb9d4..a7153ea131b 100644 --- a/src/NHibernate/Async/Loader/Loader.cs +++ b/src/NHibernate/Async/Loader/Loader.cs @@ -141,12 +141,13 @@ protected async Task LoadSingleRowAsync(DbDataReader resultSet, ISession return result; } - public async Task GetRowFromResultSetAsync(DbDataReader resultSet, ISessionImplementor session, - QueryParameters queryParameters, LockMode[] lockModeArray, - EntityKey optionalObjectKey, IList hydratedObjects, EntityKey[] keys, - bool returnProxies, IResultTransformer forcedResultTransformer, - QueryCacheResultBuilder queryCacheResultBuilder, - Action cacheBatchingHandler, CancellationToken cancellationToken) + public async Task GetRowFromResultSetAsync( + DbDataReader resultSet, ISessionImplementor session, + QueryParameters queryParameters, LockMode[] lockModeArray, + EntityKey optionalObjectKey, IList hydratedObjects, EntityKey[] keys, + bool returnProxies, IResultTransformer forcedResultTransformer, + QueryCacheResultBuilder queryCacheResultBuilder, + Action cacheBatchingHandler, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ILoadable[] persisters = EntityPersisters; @@ -341,11 +342,12 @@ private async Task DoQueryAsync(ISessionImplementor session, QueryParamet } } - public async Task InitializeEntitiesAndCollectionsAsync(IList hydratedObjects, - DbDataReader reader, - ISessionImplementor session, - bool readOnly, - CacheBatcher cacheBatcher, CancellationToken cancellationToken) + public async Task InitializeEntitiesAndCollectionsAsync( + IList hydratedObjects, + DbDataReader reader, + ISessionImplementor session, + bool readOnly, + CacheBatcher cacheBatcher, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ICollectionPersister[] collectionPersisters = CollectionPersisters; From 44072eaad7217b2ba760e765150301c7e7f6c1c0 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Mon, 12 Dec 2022 00:37:03 +0100 Subject: [PATCH 05/19] reverted evaluation of cacheable query expression --- src/NHibernate/Engine/Query/QueryPlanCache.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate/Engine/Query/QueryPlanCache.cs b/src/NHibernate/Engine/Query/QueryPlanCache.cs index 4ba579c52b3..c2b8cd9e1f6 100644 --- a/src/NHibernate/Engine/Query/QueryPlanCache.cs +++ b/src/NHibernate/Engine/Query/QueryPlanCache.cs @@ -69,7 +69,7 @@ public IQueryExpressionPlan GetHQLQueryPlan(IQueryExpression queryExpression, bo plan = new QueryExpressionPlan(queryExpression, shallow, enabledFilters, factory); // 6.0 TODO: add "CanCachePlan { get; }" to IQueryExpression interface - if(queryExpression is ICacheableQueryExpression linqExpression && linqExpression.CanCachePlan) + if (!(queryExpression is ICacheableQueryExpression linqExpression) || linqExpression.CanCachePlan) planCache.Put(key, PreparePlanToCache(plan)); else log.Debug("Query plan not cacheable"); From 67a1aac6aa18d6b996504449d651394b914bdf87 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Fri, 16 Dec 2022 09:43:13 +0100 Subject: [PATCH 06/19] various review issues solved - QueryLoaderFactory added - IQueryTranslator only publishes the Loader property of type Loader.Loader again - Type of Loader property of ITranslator is of type Loader.Loader again - ICacheableQueryExpression is only internal again - additional constructors added to QueryTranslatorImpl, QueryInfo to ensure backwards compatibility - QueryCacheResultBuilder method restored to ensure backwards compatibility --- .../Cache/QueryCacheResultBuilder.cs | 4 +++ .../Ast/ANTLR/ASTQueryTranslatorFactory.cs | 22 ++---------- .../Hql/Ast/ANTLR/QueryTranslatorImpl.cs | 36 +++++++++++++------ src/NHibernate/Hql/IQueryTranslator.cs | 3 +- src/NHibernate/IQueryExpression.cs | 2 +- src/NHibernate/Impl/MultiQueryImpl.cs | 6 ++-- src/NHibernate/Linq/ILinqQueryExpression.cs | 9 +++-- src/NHibernate/Linq/NhLinqExpression.cs | 2 +- .../Loader/Hql/IQueryLoaderFactory.cs | 21 +++++++++++ .../Loader/Hql/QueryLoaderFactory.cs | 34 ++++++++++++++++++ src/NHibernate/Multi/QueryBatchItemBase.cs | 17 +++++++++ 11 files changed, 118 insertions(+), 38 deletions(-) create mode 100644 src/NHibernate/Loader/Hql/IQueryLoaderFactory.cs create mode 100644 src/NHibernate/Loader/Hql/QueryLoaderFactory.cs diff --git a/src/NHibernate/Cache/QueryCacheResultBuilder.cs b/src/NHibernate/Cache/QueryCacheResultBuilder.cs index fe29badf5cf..97061a59511 100644 --- a/src/NHibernate/Cache/QueryCacheResultBuilder.cs +++ b/src/NHibernate/Cache/QueryCacheResultBuilder.cs @@ -15,6 +15,10 @@ public sealed class QueryCacheResultBuilder private readonly IType[] _resultTypes; private readonly Loader.Loader.QueryCacheInfo _cacheInfo; + // 6.0 TODO : remove + public static bool IsCacheWithFetches(Loader.Loader loader) + => IsCacheWithFetches((ILoader)loader); + public static bool IsCacheWithFetches(ILoader loader) { return loader.CacheTypes.Length > loader.ResultTypes.Length; diff --git a/src/NHibernate/Hql/Ast/ANTLR/ASTQueryTranslatorFactory.cs b/src/NHibernate/Hql/Ast/ANTLR/ASTQueryTranslatorFactory.cs index 41134d22f5a..b6e4e7c2c36 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/ASTQueryTranslatorFactory.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/ASTQueryTranslatorFactory.cs @@ -33,18 +33,18 @@ static IQueryTranslator[] CreateQueryTranslators( var polymorphicParsers = AstPolymorphicProcessor.Process(ast, factory); var translators = polymorphicParsers - .ToArray(hql => queryExpression is NhLinqExpression linqExpression + .ToArray(hql => queryExpression is ILinqQueryExpression linqExpression ? new QueryTranslatorImpl(queryIdentifier, hql, filters, factory, - CreateQueryLoader, + new QueryLoaderFactory(), linqExpression.GetNamedParameterTypes()) : new QueryTranslatorImpl(queryIdentifier, hql, filters, factory, - CreateQueryLoader)); + new QueryLoaderFactory())); foreach (var translator in translators) { @@ -60,21 +60,5 @@ static IQueryTranslator[] CreateQueryTranslators( return translators; } - - /// - /// Creates a query loader. - /// - /// - /// - /// - /// - private static IQueryLoader CreateQueryLoader(QueryTranslatorImpl queryTranslatorImpl, - ISessionFactoryImplementor sessionFactoryImplementor, - SelectClause selectClause) - { - return new QueryLoader(queryTranslatorImpl, - sessionFactoryImplementor, - selectClause); - } } } diff --git a/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs b/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs index d1b38966a10..5ae67f073b9 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs @@ -30,7 +30,7 @@ public partial class QueryTranslatorImpl : IFilterTranslator private readonly string _queryIdentifier; private readonly IASTNode _stageOneAst; private readonly ISessionFactoryImplementor _factory; - private readonly Func _queryLoaderFactory; + private readonly IQueryLoaderFactory _queryLoaderFactory; private readonly IDictionary> _namedParameters; private bool _shallowQuery; @@ -49,13 +49,29 @@ public partial class QueryTranslatorImpl : IFilterTranslator /// The hql query to translate /// Currently enabled filters /// The session factory constructing this translator instance. - /// A query loader factory method. + public QueryTranslatorImpl( + string queryIdentifier, + IASTNode parsedQuery, + IDictionary enabledFilters, + ISessionFactoryImplementor factory) + : this(queryIdentifier, parsedQuery, enabledFilters, factory, new QueryLoaderFactory(), null) + { + } + + /// + /// Creates a new AST-based query translator. + /// + /// The query-identifier (used in stats collection) + /// The hql query to translate + /// Currently enabled filters + /// The session factory constructing this translator instance. + /// The query loader factory. public QueryTranslatorImpl( string queryIdentifier, IASTNode parsedQuery, IDictionary enabledFilters, ISessionFactoryImplementor factory, - Func queryLoaderFactory) + IQueryLoaderFactory queryLoaderFactory) : this(queryIdentifier, parsedQuery, enabledFilters, factory, queryLoaderFactory, null) { } @@ -67,14 +83,14 @@ public QueryTranslatorImpl( /// The hql query to translate /// Currently enabled filters /// The session factory constructing this translator instance. - /// A query loader factory method. + /// The query loader factory. /// The named parameters information. public QueryTranslatorImpl( string queryIdentifier, IASTNode parsedQuery, IDictionary enabledFilters, ISessionFactoryImplementor factory, - Func queryLoaderFactory, + IQueryLoaderFactory queryLoaderFactory, IDictionary> namedParameters) { _queryIdentifier = queryIdentifier; @@ -197,11 +213,9 @@ private void ErrorIfSelect() throw new QueryExecutionRequestException("Not supported for select queries:", _queryIdentifier); } } - - public ILoader Loader - { - get { return _queryLoader; } - } + + // 6.0 TODO : change type to ILoader + public Loader.Loader Loader => _queryLoader as Loader.Loader ?? throw new NotSupportedException("Loader is not of supported type."); public virtual IType[] ActualReturnTypes { @@ -399,7 +413,7 @@ private void DoCompile(IDictionary replacements, bool shallow, S _generator = new HqlSqlGenerator(_sqlAst, _factory); _generator.Generate(); - _queryLoader = _queryLoaderFactory(this, _factory, _sqlAst.Walker.SelectClause); + _queryLoader = _queryLoaderFactory.Create(this, _factory, _sqlAst.Walker.SelectClause); } _compiled = true; diff --git a/src/NHibernate/Hql/IQueryTranslator.cs b/src/NHibernate/Hql/IQueryTranslator.cs index 7352de70469..12ad84239fd 100644 --- a/src/NHibernate/Hql/IQueryTranslator.cs +++ b/src/NHibernate/Hql/IQueryTranslator.cs @@ -114,7 +114,8 @@ public partial interface IQueryTranslator bool IsManipulationStatement { get; } - ILoader Loader { get; } + // 6.0 TODO : change type to ILoader + Loader.Loader Loader { get; } IType[] ActualReturnTypes { get; } diff --git a/src/NHibernate/IQueryExpression.cs b/src/NHibernate/IQueryExpression.cs index 93234677800..65bbe121f68 100755 --- a/src/NHibernate/IQueryExpression.cs +++ b/src/NHibernate/IQueryExpression.cs @@ -6,7 +6,7 @@ namespace NHibernate { //TODO 6.0: Merge into IQueryExpression - public interface ICacheableQueryExpression + internal interface ICacheableQueryExpression { bool CanCachePlan { get; } } diff --git a/src/NHibernate/Impl/MultiQueryImpl.cs b/src/NHibernate/Impl/MultiQueryImpl.cs index a8b15eb8df1..4862f551d4c 100644 --- a/src/NHibernate/Impl/MultiQueryImpl.cs +++ b/src/NHibernate/Impl/MultiQueryImpl.cs @@ -803,7 +803,7 @@ private int AddQueryForLaterExecutionAndReturnIndexOfQuery(System.Type resultGen public interface ITranslator { - ILoader Loader { get; } + Loader.Loader Loader { get; } IType[] ReturnTypes { get; } string[] ReturnAliases { get; } ICollection QuerySpaces { get; } @@ -818,7 +818,7 @@ public HqlTranslatorWrapper(IQueryTranslator translator) innerTranslator = translator; } - public ILoader Loader + public Loader.Loader Loader { get { return innerTranslator.Loader; } } @@ -856,7 +856,7 @@ public IType[] ReturnTypes get { return loader.ResultTypes; } } - public ILoader Loader + public Loader.Loader Loader { get { return loader; } } diff --git a/src/NHibernate/Linq/ILinqQueryExpression.cs b/src/NHibernate/Linq/ILinqQueryExpression.cs index 956b506fbbd..d23e5ca0b31 100644 --- a/src/NHibernate/Linq/ILinqQueryExpression.cs +++ b/src/NHibernate/Linq/ILinqQueryExpression.cs @@ -1,12 +1,17 @@ -namespace NHibernate.Linq +using System.Collections.Generic; +using NHibernate.Type; + +namespace NHibernate.Linq { /// /// Defines a linq query expression. /// - public interface ILinqQueryExpression: IQueryExpression, ICacheableQueryExpression + public interface ILinqQueryExpression: IQueryExpression { ExpressionToHqlTranslationResults ExpressionToHqlTranslationResults { get; } + IDictionary> GetNamedParameterTypes(); + void CopyExpressionTranslation(NhLinqExpressionCache cache); } } diff --git a/src/NHibernate/Linq/NhLinqExpression.cs b/src/NHibernate/Linq/NhLinqExpression.cs index 7ca17a4549c..a1e28b93481 100644 --- a/src/NHibernate/Linq/NhLinqExpression.cs +++ b/src/NHibernate/Linq/NhLinqExpression.cs @@ -11,7 +11,7 @@ namespace NHibernate.Linq { - public class NhLinqExpression : ILinqQueryExpression + public class NhLinqExpression : ILinqQueryExpression, ICacheableQueryExpression { public string Key { get; protected set; } diff --git a/src/NHibernate/Loader/Hql/IQueryLoaderFactory.cs b/src/NHibernate/Loader/Hql/IQueryLoaderFactory.cs new file mode 100644 index 00000000000..7063149b27d --- /dev/null +++ b/src/NHibernate/Loader/Hql/IQueryLoaderFactory.cs @@ -0,0 +1,21 @@ +using NHibernate.Engine; +using NHibernate.Hql.Ast.ANTLR; +using NHibernate.Hql.Ast.ANTLR.Tree; + +namespace NHibernate.Loader.Hql +{ + /// + /// Creates query loaders. + /// + public interface IQueryLoaderFactory + { + /// + /// Creates a query loader. + /// + /// + /// + /// + /// + IQueryLoader Create(QueryTranslatorImpl queryTranslator, ISessionFactoryImplementor factory, SelectClause selectClause); + } +} diff --git a/src/NHibernate/Loader/Hql/QueryLoaderFactory.cs b/src/NHibernate/Loader/Hql/QueryLoaderFactory.cs new file mode 100644 index 00000000000..4a9a471e9fe --- /dev/null +++ b/src/NHibernate/Loader/Hql/QueryLoaderFactory.cs @@ -0,0 +1,34 @@ +// Copyright (c) 2022 MOCCA Software GmbH. All rights reserved. +// +// All rights are reserved. Reproduction or transmission in whole or in part, +// any form or by any means, electronic, mechanical or otherwise, is prohibited +// without the prior written consent of the copyright owner. +// +// File Name: QueryLoaderFactory.cs +// Created: 12/12/2022 +// Author: Michael Kaufmann (mika) + +using NHibernate.Engine; +using NHibernate.Hql.Ast.ANTLR; +using NHibernate.Hql.Ast.ANTLR.Tree; + +namespace NHibernate.Loader.Hql +{ + /// + /// Creates query loaders. + /// + public class QueryLoaderFactory: IQueryLoaderFactory + { + /// + /// Creates a query loader. + /// + /// + /// + /// + /// + public IQueryLoader Create(QueryTranslatorImpl queryTranslator, ISessionFactoryImplementor factory, SelectClause selectClause) + { + return new QueryLoader(queryTranslator, factory, selectClause); + } + } +} diff --git a/src/NHibernate/Multi/QueryBatchItemBase.cs b/src/NHibernate/Multi/QueryBatchItemBase.cs index 7b7b86338f0..e959672e7a5 100644 --- a/src/NHibernate/Multi/QueryBatchItemBase.cs +++ b/src/NHibernate/Multi/QueryBatchItemBase.cs @@ -85,6 +85,23 @@ protected class QueryInfo : ICachingInformation, ICachingInformationWithFetches /// public CacheBatcher CacheBatcher { get; private set; } + // 6.0 TODO : remove + + /// + /// Create a new QueryInfo. + /// + /// The query parameters. + /// The loader. + /// The query spaces. + /// The session of the query. + public QueryInfo( + QueryParameters parameters, Loader.Loader loader, ISet querySpaces, + ISessionImplementor session) + :this(parameters, (ILoader)loader, querySpaces, session) + { + + } + /// /// Create a new QueryInfo. /// From 49f5a53e9f538ae295345a2e9f669a161d714645 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Fri, 16 Dec 2022 12:14:43 +0100 Subject: [PATCH 07/19] test fixed --- src/NHibernate.Test/BulkManipulation/BaseFixture.cs | 11 +---------- src/NHibernate.Test/Hql/Ast/BaseFixture.cs | 13 ++----------- .../NH2031/HqlModFuctionForMsSqlTest.cs | 13 ++----------- 3 files changed, 5 insertions(+), 32 deletions(-) diff --git a/src/NHibernate.Test/BulkManipulation/BaseFixture.cs b/src/NHibernate.Test/BulkManipulation/BaseFixture.cs index 375870fa6c9..4ef6ae63bd8 100644 --- a/src/NHibernate.Test/BulkManipulation/BaseFixture.cs +++ b/src/NHibernate.Test/BulkManipulation/BaseFixture.cs @@ -41,18 +41,9 @@ public string GetSql(string query) new HqlParseEngine(query, false, Sfi).Parse(), emptyfilters, Sfi, - CreateQueryLoader); + new QueryLoaderFactory()); qt.Compile(null, false); return qt.SQLString; } - - private static IQueryLoader CreateQueryLoader(QueryTranslatorImpl queryTranslatorImpl, - ISessionFactoryImplementor sessionFactoryImplementor, - SelectClause selectClause) - { - return new QueryLoader(queryTranslatorImpl, - sessionFactoryImplementor, - selectClause); - } } } diff --git a/src/NHibernate.Test/Hql/Ast/BaseFixture.cs b/src/NHibernate.Test/Hql/Ast/BaseFixture.cs index eeeb6299e99..a44ddd43a3a 100644 --- a/src/NHibernate.Test/Hql/Ast/BaseFixture.cs +++ b/src/NHibernate.Test/Hql/Ast/BaseFixture.cs @@ -45,19 +45,10 @@ public string GetSql(string query, IDictionary replacements) var qt = new QueryTranslatorImpl(null, new HqlParseEngine(query, false, Sfi).Parse(), emptyfilters, - Sfi, - CreateQueryLoader); + Sfi, + new QueryLoaderFactory()); qt.Compile(replacements, false); return qt.SQLString; } - - private static IQueryLoader CreateQueryLoader(QueryTranslatorImpl queryTranslatorImpl, - ISessionFactoryImplementor sessionFactoryImplementor, - SelectClause selectClause) - { - return new QueryLoader(queryTranslatorImpl, - sessionFactoryImplementor, - selectClause); - } } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH2031/HqlModFuctionForMsSqlTest.cs b/src/NHibernate.Test/NHSpecificTest/NH2031/HqlModFuctionForMsSqlTest.cs index 37e60c833a6..fa76e0aa034 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2031/HqlModFuctionForMsSqlTest.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2031/HqlModFuctionForMsSqlTest.cs @@ -33,19 +33,10 @@ public string GetSql(string query) var qt = new QueryTranslatorImpl(null, new HqlParseEngine(query, false, Sfi).Parse(), CollectionHelper.EmptyDictionary(), - Sfi, - CreateQueryLoader); + Sfi, + new QueryLoaderFactory()); qt.Compile(null, false); return qt.SQLString; } - - private static IQueryLoader CreateQueryLoader(QueryTranslatorImpl queryTranslatorImpl, - ISessionFactoryImplementor sessionFactoryImplementor, - SelectClause selectClause) - { - return new QueryLoader(queryTranslatorImpl, - sessionFactoryImplementor, - selectClause); - } } } From cc27627df95fc7ff5a1b71bedc8fb146268c50d0 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sun, 18 Dec 2022 23:39:02 +0100 Subject: [PATCH 08/19] tests added --- .../CustomQueryLoaderFixture.cs | 117 ++++++++++ .../QueryTranslator/CustomQueryLoader.cs | 202 ++++++++++++++++++ .../CustomQueryLoaderFactory.cs | 20 ++ .../CustomQueryLoaderFixture.cs | 105 +++++++++ .../CustomQueryTranslatorFactory.cs | 83 +++++++ 5 files changed, 527 insertions(+) create mode 100644 src/NHibernate.Test/Async/QueryTranslator/CustomQueryLoaderFixture.cs create mode 100644 src/NHibernate.Test/QueryTranslator/CustomQueryLoader.cs create mode 100644 src/NHibernate.Test/QueryTranslator/CustomQueryLoaderFactory.cs create mode 100644 src/NHibernate.Test/QueryTranslator/CustomQueryLoaderFixture.cs create mode 100644 src/NHibernate.Test/QueryTranslator/CustomQueryTranslatorFactory.cs diff --git a/src/NHibernate.Test/Async/QueryTranslator/CustomQueryLoaderFixture.cs b/src/NHibernate.Test/Async/QueryTranslator/CustomQueryLoaderFixture.cs new file mode 100644 index 00000000000..7f3b251feb8 --- /dev/null +++ b/src/NHibernate.Test/Async/QueryTranslator/CustomQueryLoaderFixture.cs @@ -0,0 +1,117 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System.Linq; +using NHibernate.Cfg; +using NHibernate.DomainModel.Northwind.Entities; +using NUnit.Framework; +using NHibernate.Linq; + +namespace NHibernate.Test.QueryTranslator +{ + using System.Threading.Tasks; + [TestFixture] + internal sealed class CustomQueryLoaderFixtureAsync : TestCase + { + private ISession _session; + private ITransaction _transaction; + + protected override string[] Mappings => new[] + { + "Northwind.Mappings.Customer.hbm.xml", + "Northwind.Mappings.Employee.hbm.xml", + "Northwind.Mappings.Order.hbm.xml", + "Northwind.Mappings.OrderLine.hbm.xml", + "Northwind.Mappings.Product.hbm.xml", + "Northwind.Mappings.ProductCategory.hbm.xml", + "Northwind.Mappings.Region.hbm.xml", + "Northwind.Mappings.Shipper.hbm.xml", + "Northwind.Mappings.Supplier.hbm.xml", + "Northwind.Mappings.Territory.hbm.xml", + "Northwind.Mappings.AnotherEntity.hbm.xml", + "Northwind.Mappings.Role.hbm.xml", + "Northwind.Mappings.User.hbm.xml", + "Northwind.Mappings.TimeSheet.hbm.xml", + "Northwind.Mappings.Animal.hbm.xml", + "Northwind.Mappings.Patient.hbm.xml", + "Northwind.Mappings.NumericEntity.hbm.xml" + }; + + protected override string MappingsAssembly => "NHibernate.DomainModel"; + + protected override void Configure(Configuration configuration) + { + configuration.SetProperty(Environment.QueryTranslator, typeof(CustomQueryTranslatorFactory).AssemblyQualifiedName); + } + + protected override void OnSetUp() + { + base.OnSetUp(); + + _session = OpenSession(); + _transaction = _session.BeginTransaction(); + + var customer = new Customer + { + CustomerId = "C1", + CompanyName = "Company" + }; + _session.Save(customer); + _session.Flush(); + _session.Clear(); + } + + protected override void OnTearDown() + { + base.OnTearDown(); + + _transaction.Rollback(); + _transaction.Dispose(); + _session.Close(); + _session.Dispose(); + } + + [Test] + public async Task CriteriaQueryTestAsync() + { + var customers = await (_session.CreateCriteria(typeof(Customer)) + .ListAsync()); + + Assert.AreEqual(1, customers.Count); + } + + [Test] + public async Task HqlQueryTestAsync() + { + var customers = await (_session.CreateQuery("select c from Customer c") + .ListAsync()); + + Assert.AreEqual(1, customers.Count); + } + + [Test] + public async Task LinqQueryTestAsync() + { + var customers = await (_session.Query() + .ToListAsync()); + + Assert.AreEqual(1, customers.Count); + } + + [Test] + public async Task QueryOverQueryTestAsync() + { + var customers = await (_session.QueryOver() + .ListAsync()); + + Assert.AreEqual(1, customers.Count); + } + } +} diff --git a/src/NHibernate.Test/QueryTranslator/CustomQueryLoader.cs b/src/NHibernate.Test/QueryTranslator/CustomQueryLoader.cs new file mode 100644 index 00000000000..621716c74d6 --- /dev/null +++ b/src/NHibernate.Test/QueryTranslator/CustomQueryLoader.cs @@ -0,0 +1,202 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data.Common; +using System.Threading; +using System.Threading.Tasks; +using NHibernate.Cache; +using NHibernate.Engine; +using NHibernate.Event; +using NHibernate.Loader.Hql; +using NHibernate.Persister; +using NHibernate.Persister.Entity; +using NHibernate.SqlCommand; +using NHibernate.Transform; +using NHibernate.Type; + +namespace NHibernate.Test.QueryTranslator +{ + internal sealed class CustomQueryLoader: IQueryLoader + { + private readonly IQueryLoader _queryLoader; + + public CustomQueryLoader(IQueryLoader queryLoader) + { + _queryLoader = queryLoader; + } + + public Task GetRowFromResultSetAsync( + DbDataReader resultSet, + ISessionImplementor session, + QueryParameters queryParameters, + LockMode[] lockModeArray, + EntityKey optionalObjectKey, + IList hydratedObjects, + EntityKey[] keys, + bool returnProxies, + IResultTransformer forcedResultTransformer, + QueryCacheResultBuilder queryCacheResultBuilder, + Action cacheBatchingHandler, + CancellationToken cancellationToken) + { + return _queryLoader.GetRowFromResultSetAsync(resultSet, session, queryParameters, lockModeArray, optionalObjectKey, hydratedObjects, keys, returnProxies, forcedResultTransformer, queryCacheResultBuilder, cacheBatchingHandler, cancellationToken); + } + + public Task InitializeEntitiesAndCollectionsAsync( + IList hydratedObjects, + DbDataReader reader, + ISessionImplementor session, + bool readOnly, + CacheBatcher cacheBatcher, + CancellationToken cancellationToken) + { + return _queryLoader.InitializeEntitiesAndCollectionsAsync(hydratedObjects, reader, session, readOnly, cacheBatcher, cancellationToken); + } + + public Task LoadCollectionAsync(ISessionImplementor session, object id, IType type, CancellationToken cancellationToken) + { + return _queryLoader.LoadCollectionAsync(session, id, type, cancellationToken); + } + + public Task LoadCollectionBatchAsync( + ISessionImplementor session, + object[] ids, + IType type, + CancellationToken cancellationToken) + { + return _queryLoader.LoadCollectionBatchAsync(session, ids, type, cancellationToken); + } + + public bool IsSubselectLoadingEnabled => _queryLoader.IsSubselectLoadingEnabled; + + public IType[] ResultTypes => _queryLoader.ResultTypes; + + public IType[] CacheTypes => _queryLoader.CacheTypes; + + public Loader.Loader.QueryCacheInfo CacheInfo => _queryLoader.CacheInfo; + + public ISessionFactoryImplementor Factory => _queryLoader.Factory; + + public SqlString SqlString => _queryLoader.SqlString; + + public ILoadable[] EntityPersisters => _queryLoader.EntityPersisters; + + public string QueryIdentifier => _queryLoader.QueryIdentifier; + + public LockMode[] GetLockModes(IDictionary lockModes) + { + return _queryLoader.GetLockModes(lockModes); + } + + public object GetRowFromResultSet( + DbDataReader resultSet, + ISessionImplementor session, + QueryParameters queryParameters, + LockMode[] lockModeArray, + EntityKey optionalObjectKey, + IList hydratedObjects, + EntityKey[] keys, + bool returnProxies, + IResultTransformer forcedResultTransformer, + QueryCacheResultBuilder queryCacheResultBuilder, + Action cacheBatchingHandler) + { + return _queryLoader.GetRowFromResultSet(resultSet, session, queryParameters, lockModeArray, optionalObjectKey, hydratedObjects, keys, returnProxies, forcedResultTransformer, queryCacheResultBuilder, cacheBatchingHandler); + } + + public void CreateSubselects(List keys, QueryParameters queryParameters, ISessionImplementor session) + { + _queryLoader.CreateSubselects(keys, queryParameters, session); + } + + public void InitializeEntitiesAndCollections( + IList hydratedObjects, + DbDataReader reader, + ISessionImplementor session, + bool readOnly, + CacheBatcher cacheBatcher) + { + _queryLoader.InitializeEntitiesAndCollections(hydratedObjects, reader, session, readOnly, cacheBatcher); + } + + public IList GetResultList(IList results, IResultTransformer resultTransformer) + { + return _queryLoader.GetResultList(results, resultTransformer); + } + + public bool UseLimit(RowSelection selection, Dialect.Dialect dialect) + { + return _queryLoader.UseLimit(selection, dialect); + } + + public void LoadCollection(ISessionImplementor session, object id, IType type) + { + _queryLoader.LoadCollection(session, id, type); + } + + public void LoadCollectionBatch(ISessionImplementor session, object[] ids, IType type) + { + _queryLoader.LoadCollectionBatch(session, ids, type); + } + + public bool IsCacheable(QueryParameters queryParameters) + { + return _queryLoader.IsCacheable(queryParameters); + } + + public bool IsCacheable(QueryParameters queryParameters, bool supportsQueryCache, IEnumerable persisters) + { + return _queryLoader.IsCacheable(queryParameters, supportsQueryCache, persisters); + } + + public ISqlCommand CreateSqlCommand(QueryParameters queryParameters, ISessionImplementor session) + { + return _queryLoader.CreateSqlCommand(queryParameters, session); + } + + public void AutoDiscoverTypes(DbDataReader rs, QueryParameters queryParameters, IResultTransformer forcedResultTransformer) + { + _queryLoader.AutoDiscoverTypes(rs, queryParameters, forcedResultTransformer); + } + + public IList TransformCacheableResults(QueryParameters queryParameters, CacheableResultTransformer transformer, IList result) + { + return _queryLoader.TransformCacheableResults(queryParameters, transformer, result); + } + + public void HandleEmptyCollections(object[] keys, object resultSetId, ISessionImplementor session) + { + _queryLoader.HandleEmptyCollections(keys, resultSetId, session); + } + + public void StopLoadingCollections(ISessionImplementor session, DbDataReader reader) + { + _queryLoader.StopLoadingCollections(session, reader); + } + + public QueryKey GenerateQueryKey(ISessionImplementor session, QueryParameters queryParameters) + { + return _queryLoader.GenerateQueryKey(session, queryParameters); + } + + public IList List(ISessionImplementor session, QueryParameters queryParameters) + { + return _queryLoader.List(session, queryParameters); + } + + public IEnumerable GetEnumerable(QueryParameters queryParameters, IEventSource session) + { + return _queryLoader.GetEnumerable(queryParameters, session); + } + + public Task ListAsync(ISessionImplementor session, QueryParameters queryParameters, CancellationToken cancellationToken) + { + return _queryLoader.ListAsync(session, queryParameters, cancellationToken); + } + + public Task GetEnumerableAsync(QueryParameters queryParameters, IEventSource session, CancellationToken cancellationToken) + { + return _queryLoader.GetEnumerableAsync(queryParameters, session, cancellationToken); + } + } +} diff --git a/src/NHibernate.Test/QueryTranslator/CustomQueryLoaderFactory.cs b/src/NHibernate.Test/QueryTranslator/CustomQueryLoaderFactory.cs new file mode 100644 index 00000000000..ea6d8d6524b --- /dev/null +++ b/src/NHibernate.Test/QueryTranslator/CustomQueryLoaderFactory.cs @@ -0,0 +1,20 @@ +using NHibernate.Engine; +using NHibernate.Hql.Ast.ANTLR; +using NHibernate.Hql.Ast.ANTLR.Tree; +using NHibernate.Loader.Hql; + +namespace NHibernate.Test.QueryTranslator +{ + internal sealed class CustomQueryLoaderFactory: IQueryLoaderFactory + { + public IQueryLoader Create( + QueryTranslatorImpl queryTranslator, + ISessionFactoryImplementor factory, + SelectClause selectClause) + { + return new CustomQueryLoader(new QueryLoader(queryTranslator, + factory, + selectClause)); + } + } +} diff --git a/src/NHibernate.Test/QueryTranslator/CustomQueryLoaderFixture.cs b/src/NHibernate.Test/QueryTranslator/CustomQueryLoaderFixture.cs new file mode 100644 index 00000000000..3331e402639 --- /dev/null +++ b/src/NHibernate.Test/QueryTranslator/CustomQueryLoaderFixture.cs @@ -0,0 +1,105 @@ +using System.Linq; +using NHibernate.Cfg; +using NHibernate.DomainModel.Northwind.Entities; +using NUnit.Framework; + +namespace NHibernate.Test.QueryTranslator +{ + [TestFixture] + internal sealed class CustomQueryLoaderFixture : TestCase + { + private ISession _session; + private ITransaction _transaction; + + protected override string[] Mappings => new[] + { + "Northwind.Mappings.Customer.hbm.xml", + "Northwind.Mappings.Employee.hbm.xml", + "Northwind.Mappings.Order.hbm.xml", + "Northwind.Mappings.OrderLine.hbm.xml", + "Northwind.Mappings.Product.hbm.xml", + "Northwind.Mappings.ProductCategory.hbm.xml", + "Northwind.Mappings.Region.hbm.xml", + "Northwind.Mappings.Shipper.hbm.xml", + "Northwind.Mappings.Supplier.hbm.xml", + "Northwind.Mappings.Territory.hbm.xml", + "Northwind.Mappings.AnotherEntity.hbm.xml", + "Northwind.Mappings.Role.hbm.xml", + "Northwind.Mappings.User.hbm.xml", + "Northwind.Mappings.TimeSheet.hbm.xml", + "Northwind.Mappings.Animal.hbm.xml", + "Northwind.Mappings.Patient.hbm.xml", + "Northwind.Mappings.NumericEntity.hbm.xml" + }; + + protected override string MappingsAssembly => "NHibernate.DomainModel"; + + protected override void Configure(Configuration configuration) + { + configuration.SetProperty(Environment.QueryTranslator, typeof(CustomQueryTranslatorFactory).AssemblyQualifiedName); + } + + protected override void OnSetUp() + { + base.OnSetUp(); + + _session = OpenSession(); + _transaction = _session.BeginTransaction(); + + var customer = new Customer + { + CustomerId = "C1", + CompanyName = "Company" + }; + _session.Save(customer); + _session.Flush(); + _session.Clear(); + } + + protected override void OnTearDown() + { + base.OnTearDown(); + + _transaction.Rollback(); + _transaction.Dispose(); + _session.Close(); + _session.Dispose(); + } + + [Test] + public void CriteriaQueryTest() + { + var customers = _session.CreateCriteria(typeof(Customer)) + .List(); + + Assert.AreEqual(1, customers.Count); + } + + [Test] + public void HqlQueryTest() + { + var customers = _session.CreateQuery("select c from Customer c") + .List(); + + Assert.AreEqual(1, customers.Count); + } + + [Test] + public void LinqQueryTest() + { + var customers = _session.Query() + .ToList(); + + Assert.AreEqual(1, customers.Count); + } + + [Test] + public void QueryOverQueryTest() + { + var customers = _session.QueryOver() + .List(); + + Assert.AreEqual(1, customers.Count); + } + } +} diff --git a/src/NHibernate.Test/QueryTranslator/CustomQueryTranslatorFactory.cs b/src/NHibernate.Test/QueryTranslator/CustomQueryTranslatorFactory.cs new file mode 100644 index 00000000000..c74907217ed --- /dev/null +++ b/src/NHibernate.Test/QueryTranslator/CustomQueryTranslatorFactory.cs @@ -0,0 +1,83 @@ +using System.Collections.Generic; +using NHibernate.Engine; +using NHibernate.Hql; +using NHibernate.Hql.Ast.ANTLR; +using NHibernate.Hql.Ast.ANTLR.Tree; +using NHibernate.Linq; +using NHibernate.Loader.Hql; +using NHibernate.Type; + +namespace NHibernate.Test.QueryTranslator +{ + internal sealed class CustomQueryTranslatorFactory: IQueryTranslatorFactory + { + public IQueryTranslator[] CreateQueryTranslators(IQueryExpression queryExpression, string collectionRole, bool shallow, IDictionary filters, ISessionFactoryImplementor factory) + { + return CreateQueryTranslators(queryExpression, + queryExpression.Translate(factory, collectionRole != null), + queryExpression.Key, + collectionRole, + shallow, + filters, + factory); + } + + private static IQueryTranslator[] CreateQueryTranslators( + IQueryExpression queryExpression, + IASTNode ast, + string queryIdentifier, + string collectionRole, + bool shallow, + IDictionary filters, + ISessionFactoryImplementor factory) + { + var polymorphicParsers = AstPolymorphicProcessor.Process(ast, factory); + + IQueryTranslator[] translators = new IQueryTranslator[polymorphicParsers.Length]; + for(int i = 0; i < polymorphicParsers.Length; i++) + { + var parser = polymorphicParsers[i]; + + IFilterTranslator translator = CreateTranslator(queryIdentifier, + filters, + factory, + parser, + queryExpression); + if(collectionRole == null) + { + translator.Compile(factory.Settings.QuerySubstitutions, shallow); + } + else + { + translator.Compile(collectionRole, factory.Settings.QuerySubstitutions, shallow); + } + + translators[i] = translator; + } + + return translators; + } + + private static QueryTranslatorImpl CreateTranslator( + string queryIdentifier, + IDictionary filters, + ISessionFactoryImplementor factory, + IASTNode parser, + IQueryExpression queryExpression) + { + IDictionary> namedParameterTypes = new Dictionary>(); + + if(queryExpression is ILinqQueryExpression linqQueryExpression) + { + namedParameterTypes = linqQueryExpression.GetNamedParameterTypes(); + } + + return new QueryTranslatorImpl(queryIdentifier, + parser, + filters, + factory, + new CustomQueryLoaderFactory(), + namedParameterTypes); + } + } +} From 0ecd914753ecf5904af0963619adad68be482c94 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Tue, 27 Dec 2022 19:48:48 +0100 Subject: [PATCH 09/19] review issue fixed --- src/NHibernate/Multi/QueryBatchItemBase.cs | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/src/NHibernate/Multi/QueryBatchItemBase.cs b/src/NHibernate/Multi/QueryBatchItemBase.cs index e959672e7a5..7920e291c73 100644 --- a/src/NHibernate/Multi/QueryBatchItemBase.cs +++ b/src/NHibernate/Multi/QueryBatchItemBase.cs @@ -5,7 +5,6 @@ using System.Linq; using NHibernate.Cache; using NHibernate.Engine; -using NHibernate.Loader; using NHibernate.SqlCommand; using NHibernate.Type; using NHibernate.Util; @@ -29,10 +28,11 @@ public abstract partial class QueryBatchItemBase : IQueryBatchItem /// The query loader. /// - public ILoader Loader { get; set; } + public Loader.Loader Loader { get; set; } /// /// The query result. @@ -97,21 +97,6 @@ protected class QueryInfo : ICachingInformation, ICachingInformationWithFetches public QueryInfo( QueryParameters parameters, Loader.Loader loader, ISet querySpaces, ISessionImplementor session) - :this(parameters, (ILoader)loader, querySpaces, session) - { - - } - - /// - /// Create a new QueryInfo. - /// - /// The query parameters. - /// The loader. - /// The query spaces. - /// The session of the query. - public QueryInfo( - QueryParameters parameters, ILoader loader, ISet querySpaces, - ISessionImplementor session) { Parameters = parameters; Loader = loader; From d5a782af6b63884fa15492f7a4ece53edbda50a1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 27 Dec 2022 18:54:45 +0000 Subject: [PATCH 10/19] Generate async files --- src/NHibernate/Async/Multi/QueryBatchItemBase.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/NHibernate/Async/Multi/QueryBatchItemBase.cs b/src/NHibernate/Async/Multi/QueryBatchItemBase.cs index f596da92f44..e590cc77f6f 100644 --- a/src/NHibernate/Async/Multi/QueryBatchItemBase.cs +++ b/src/NHibernate/Async/Multi/QueryBatchItemBase.cs @@ -15,7 +15,6 @@ using System.Linq; using NHibernate.Cache; using NHibernate.Engine; -using NHibernate.Loader; using NHibernate.SqlCommand; using NHibernate.Type; using NHibernate.Util; From bd093207f14c8e7258097ba499c804865a84c786 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericdelaporte@users.noreply.github.com> Date: Sun, 1 Jan 2023 17:10:57 +0100 Subject: [PATCH 11/19] Avoid some possible binary breaking change --- src/NHibernate/Async/Impl/MultiQueryImpl.cs | 20 +++---- .../Async/Multi/QueryBatchItemBase.cs | 10 ++-- .../Cache/QueryCacheResultBuilder.cs | 5 +- .../Hql/Ast/ANTLR/QueryTranslatorImpl.cs | 14 +++-- src/NHibernate/Hql/IFilterTranslator.cs | 2 +- src/NHibernate/Hql/IQueryTranslator.cs | 52 ++++++++++++++++++- src/NHibernate/Impl/MultiQueryImpl.cs | 52 +++++++++++++++++++ src/NHibernate/Loader/Loader.cs | 2 +- src/NHibernate/Multi/CriteriaBatchItem.cs | 3 +- src/NHibernate/Multi/QueryBatchItem.cs | 2 +- src/NHibernate/Multi/QueryBatchItemBase.cs | 51 ++++++++++++------ 11 files changed, 170 insertions(+), 43 deletions(-) diff --git a/src/NHibernate/Async/Impl/MultiQueryImpl.cs b/src/NHibernate/Async/Impl/MultiQueryImpl.cs index 3ecc5e5b933..5d5d3ed7377 100644 --- a/src/NHibernate/Async/Impl/MultiQueryImpl.cs +++ b/src/NHibernate/Async/Impl/MultiQueryImpl.cs @@ -103,28 +103,29 @@ protected async Task> DoListAsync(CancellationToken cancellationTok { ITranslator translator = Translators[i]; QueryParameters parameter = Parameters[i]; + var loader = translator.GetQueryLoader(); - int entitySpan = translator.Loader.EntityPersisters.Length; + int entitySpan = loader.EntityPersisters.Length; hydratedObjects[i] = entitySpan > 0 ? new List() : null; RowSelection selection = parameter.RowSelection; int maxRows = Loader.Loader.HasMaxRows(selection) ? selection.MaxRows : int.MaxValue; - if (!dialect.SupportsLimitOffset || !translator.Loader.UseLimit(selection, dialect)) + if (!dialect.SupportsLimitOffset || !loader.UseLimit(selection, dialect)) { await (Loader.Loader.AdvanceAsync(reader, selection, cancellationToken)).ConfigureAwait(false); } if (parameter.HasAutoDiscoverScalarTypes) { - translator.Loader.AutoDiscoverTypes(reader, parameter, null); + loader.AutoDiscoverTypes(reader, parameter, null); } - LockMode[] lockModeArray = translator.Loader.GetLockModes(parameter.LockModes); + LockMode[] lockModeArray = loader.GetLockModes(parameter.LockModes); EntityKey optionalObjectKey = Loader.Loader.GetOptionalObjectKey(parameter, session); - createSubselects[i] = translator.Loader.IsSubselectLoadingEnabled; + createSubselects[i] = loader.IsSubselectLoadingEnabled; subselectResultKeys[i] = createSubselects[i] ? new List() : null; - translator.Loader.HandleEmptyCollections(parameter.CollectionKeys, reader, session); + loader.HandleEmptyCollections(parameter.CollectionKeys, reader, session); EntityKey[] keys = new EntityKey[entitySpan]; // we can reuse it each time if (log.IsDebugEnabled()) @@ -142,7 +143,7 @@ protected async Task> DoListAsync(CancellationToken cancellationTok } rowCount++; - object result = await (translator.Loader.GetRowFromResultSetAsync( + object result = await (loader.GetRowFromResultSetAsync( reader, session, parameter, lockModeArray, optionalObjectKey, hydratedObjects[i], keys, true, null, null, (persister, data) => cacheBatcher.AddToBatch(persister, data), cancellationToken)).ConfigureAwait(false); tempResults.Add(result); @@ -173,12 +174,13 @@ protected async Task> DoListAsync(CancellationToken cancellationTok { ITranslator translator = translators[i]; QueryParameters parameter = parameters[i]; + var loader = translator.GetQueryLoader(); - await (translator.Loader.InitializeEntitiesAndCollectionsAsync(hydratedObjects[i], reader, session, false, cacheBatcher, cancellationToken)).ConfigureAwait(false); + await (loader.InitializeEntitiesAndCollectionsAsync(hydratedObjects[i], reader, session, false, cacheBatcher, cancellationToken)).ConfigureAwait(false); if (createSubselects[i]) { - translator.Loader.CreateSubselects(subselectResultKeys[i], parameter, session); + loader.CreateSubselects(subselectResultKeys[i], parameter, session); } } diff --git a/src/NHibernate/Async/Multi/QueryBatchItemBase.cs b/src/NHibernate/Async/Multi/QueryBatchItemBase.cs index e590cc77f6f..3bce616273d 100644 --- a/src/NHibernate/Async/Multi/QueryBatchItemBase.cs +++ b/src/NHibernate/Async/Multi/QueryBatchItemBase.cs @@ -42,7 +42,7 @@ public async Task ProcessResultsSetAsync(DbDataReader reader, CancellationT for (var i = 0; i < _queryInfos.Count; i++) { var queryInfo = _queryInfos[i]; - var loader = queryInfo.Loader; + var loader = queryInfo.QueryLoader; var queryParameters = queryInfo.Parameters; //Skip processing for items already loaded from cache @@ -150,20 +150,20 @@ public async Task ProcessResultsAsync(CancellationToken cancellationToken) var queryInfo = _queryInfos[i]; if (_subselectResultKeys[i] != null) { - queryInfo.Loader.CreateSubselects(_subselectResultKeys[i], queryInfo.Parameters, Session); + queryInfo.QueryLoader.CreateSubselects(_subselectResultKeys[i], queryInfo.Parameters, Session); } if (queryInfo.IsCacheable) { if (queryInfo.IsResultFromCache) { - var queryCacheBuilder = new QueryCacheResultBuilder(queryInfo.Loader); + var queryCacheBuilder = new QueryCacheResultBuilder(queryInfo.QueryLoader); queryInfo.Result = queryCacheBuilder.GetResultList(queryInfo.Result); } // This transformation must not be applied to ResultToCache. queryInfo.Result = - queryInfo.Loader.TransformCacheableResults( + queryInfo.QueryLoader.TransformCacheableResults( queryInfo.Parameters, queryInfo.CacheKey.ResultTransformer, queryInfo.Result); } } @@ -188,7 +188,7 @@ private async Task InitializeEntitiesAndCollectionsAsync(DbDataReader reader, Li var queryInfo = _queryInfos[i]; if (queryInfo.IsResultFromCache) continue; - await (queryInfo.Loader.InitializeEntitiesAndCollectionsAsync( + await (queryInfo.QueryLoader.InitializeEntitiesAndCollectionsAsync( hydratedObjects[i], reader, Session, queryInfo.Parameters.IsReadOnly(Session), queryInfo.CacheBatcher, cancellationToken)).ConfigureAwait(false); } diff --git a/src/NHibernate/Cache/QueryCacheResultBuilder.cs b/src/NHibernate/Cache/QueryCacheResultBuilder.cs index 97061a59511..3607a4c9da7 100644 --- a/src/NHibernate/Cache/QueryCacheResultBuilder.cs +++ b/src/NHibernate/Cache/QueryCacheResultBuilder.cs @@ -15,10 +15,11 @@ public sealed class QueryCacheResultBuilder private readonly IType[] _resultTypes; private readonly Loader.Loader.QueryCacheInfo _cacheInfo; - // 6.0 TODO : remove + // Since 5.5. + [Obsolete("Use overload taking an ILoader instead.")] public static bool IsCacheWithFetches(Loader.Loader loader) => IsCacheWithFetches((ILoader)loader); - + public static bool IsCacheWithFetches(ILoader loader) { return loader.CacheTypes.Length > loader.ResultTypes.Length; diff --git a/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs b/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs index 5ae67f073b9..bbf6fdfb48d 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs @@ -23,7 +23,7 @@ namespace NHibernate.Hql.Ast.ANTLR { [CLSCompliant(false)] - public partial class QueryTranslatorImpl : IFilterTranslator + public partial class QueryTranslatorImpl : IFilterTranslator, IQueryTranslatorWithCustomizableLoader { private static readonly INHibernateLogger log = NHibernateLogger.For(typeof(QueryTranslatorImpl)); @@ -49,6 +49,8 @@ public partial class QueryTranslatorImpl : IFilterTranslator /// The hql query to translate /// Currently enabled filters /// The session factory constructing this translator instance. + // Since 5.5. + [Obsolete("Use overload taking an IQueryLoaderFactory.")] public QueryTranslatorImpl( string queryIdentifier, IASTNode parsedQuery, @@ -213,9 +215,13 @@ private void ErrorIfSelect() throw new QueryExecutionRequestException("Not supported for select queries:", _queryIdentifier); } } - - // 6.0 TODO : change type to ILoader - public Loader.Loader Loader => _queryLoader as Loader.Loader ?? throw new NotSupportedException("Loader is not of supported type."); + + // Since 5.5 + [Obsolete("Use QueryLoader property instead")] + public Loader.Loader Loader => _queryLoader as Loader.Loader ?? throw new NotSupportedException("Custom loader is not supported."); + + /// + public ILoader QueryLoader => _queryLoader; public virtual IType[] ActualReturnTypes { diff --git a/src/NHibernate/Hql/IFilterTranslator.cs b/src/NHibernate/Hql/IFilterTranslator.cs index 4916b95e7ac..67fc3314352 100644 --- a/src/NHibernate/Hql/IFilterTranslator.cs +++ b/src/NHibernate/Hql/IFilterTranslator.cs @@ -16,4 +16,4 @@ public interface IFilterTranslator : IQueryTranslator /// Does this represent a shallow (scalar or entity-id) select? void Compile(string collectionRole, IDictionary replacements, bool shallow); } -} \ No newline at end of file +} diff --git a/src/NHibernate/Hql/IQueryTranslator.cs b/src/NHibernate/Hql/IQueryTranslator.cs index 12ad84239fd..93fee2aaf80 100644 --- a/src/NHibernate/Hql/IQueryTranslator.cs +++ b/src/NHibernate/Hql/IQueryTranslator.cs @@ -1,3 +1,4 @@ +using System; using System.Collections; using System.Collections.Generic; using NHibernate.Engine; @@ -114,11 +115,58 @@ public partial interface IQueryTranslator bool IsManipulationStatement { get; } - // 6.0 TODO : change type to ILoader + // 6.0 TODO : replace by ILoader QueryLoader. + // Since 5.5. + [Obsolete("Use GetQueryLoader extension method instead.")] Loader.Loader Loader { get; } IType[] ActualReturnTypes { get; } - ParameterMetadata BuildParameterMetadata(); + ParameterMetadata BuildParameterMetadata(); + } + + // 6.0 Todo : remove. + /// + /// Transitional interface for . + /// + public interface IQueryTranslatorWithCustomizableLoader + { + // 6.0 : move into IQueryTranslator. + /// + /// The query loader. + /// + ILoader QueryLoader { get; } + } + + // 6.0 TODO: drop. + public static class QueryTranslatorExtensions + { + private static readonly INHibernateLogger Log = NHibernateLogger.For(typeof(QueryTranslatorExtensions)); + + // Non thread safe: not an issue, at worst it will cause a few more logs than one. + // Does not handle the possibility of using multiple different obsoleted query translator implementations: + // only the first encountered will be logged. + private static bool _hasWarnedForObsoleteQueryTranslator; + + /// + /// Get the query loader. + /// + /// The query translator. + /// The query loader. + public static ILoader GetQueryLoader(this IQueryTranslator queryTranslator) + { + if (queryTranslator is IQueryTranslatorWithCustomizableLoader qtwcl) + return qtwcl.QueryLoader; + + if (!_hasWarnedForObsoleteQueryTranslator) + { + _hasWarnedForObsoleteQueryTranslator = true; + Log.Warn("{0} is obsolete, it should implement {1} to support customizable loaders", queryTranslator, nameof(IQueryTranslatorWithCustomizableLoader)); + } + +#pragma warning disable CS0618 // Type or member is obsolete + return queryTranslator.Loader; +#pragma warning restore CS0618 // Type or member is obsolete + } } } diff --git a/src/NHibernate/Impl/MultiQueryImpl.cs b/src/NHibernate/Impl/MultiQueryImpl.cs index 4862f551d4c..90c905501ef 100644 --- a/src/NHibernate/Impl/MultiQueryImpl.cs +++ b/src/NHibernate/Impl/MultiQueryImpl.cs @@ -803,12 +803,60 @@ private int AddQueryForLaterExecutionAndReturnIndexOfQuery(System.Type resultGen public interface ITranslator { + // 6.0 TODO : replace by ILoader QueryLoader. + // Since 5.5. + [Obsolete("Use GetQueryLoader extension method instead.")] Loader.Loader Loader { get; } IType[] ReturnTypes { get; } string[] ReturnAliases { get; } ICollection QuerySpaces { get; } } + // 6.0 Todo : remove. + /// + /// Transitional interface for . + /// + public interface ITranslatorWithCustomizableLoader : ITranslator + { + // 6.0 : move into ITranslator. + /// + /// The query loader. + /// + ILoader QueryLoader { get; } + } + + // 6.0 TODO: drop. + public static class TranslatorExtensions + { + private static readonly INHibernateLogger Log = NHibernateLogger.For(typeof(TranslatorExtensions)); + + // Non thread safe: not an issue, at worst it will cause a few more logs than one. + // Does not handle the possibility of using multiple different obsoleted translator implementations: + // only the first encountered will be logged. + private static bool _hasWarnedForObsoleteTranslator; + + /// + /// Get the query loader. + /// + /// The query translator. + /// The query loader. + public static ILoader GetQueryLoader(this ITranslator translator) + { + if (translator is ITranslatorWithCustomizableLoader twcl) + return twcl.QueryLoader; + + if (!_hasWarnedForObsoleteTranslator) + { + _hasWarnedForObsoleteTranslator = true; + Log.Warn("{0} is obsolete, it should implement {1} to support customizable loaders", translator, nameof(ITranslatorWithCustomizableLoader)); + } + +#pragma warning disable CS0618 // Type or member is obsolete + return translator.Loader; +#pragma warning restore CS0618 // Type or member is obsolete + } + } + internal class HqlTranslatorWrapper : ITranslator { private readonly IQueryTranslator innerTranslator; @@ -818,11 +866,15 @@ public HqlTranslatorWrapper(IQueryTranslator translator) innerTranslator = translator; } + [Obsolete("Use QueryLoader instead.")] public Loader.Loader Loader { get { return innerTranslator.Loader; } } + /// + public ILoader QueryLoader => innerTranslator.GetQueryLoader(); + public IType[] ReturnTypes { get { return innerTranslator.ActualReturnTypes; } diff --git a/src/NHibernate/Loader/Loader.cs b/src/NHibernate/Loader/Loader.cs index e61557976a9..53294db26de 100644 --- a/src/NHibernate/Loader/Loader.cs +++ b/src/NHibernate/Loader/Loader.cs @@ -1921,7 +1921,7 @@ public QueryKey GenerateQueryKey(ISessionImplementor session, QueryParameters qu private CacheableResultTransformer CreateCacheableResultTransformer(QueryParameters queryParameters) { - bool skipTransformer = QueryCacheResultBuilder.IsCacheWithFetches(this); + bool skipTransformer = QueryCacheResultBuilder.IsCacheWithFetches((ILoader)this); return CacheableResultTransformer.Create( queryParameters.ResultTransformer, ResultRowAliases, IncludeInResultRow, diff --git a/src/NHibernate/Multi/CriteriaBatchItem.cs b/src/NHibernate/Multi/CriteriaBatchItem.cs index 6c6e6bfc150..8fdf37ea536 100644 --- a/src/NHibernate/Multi/CriteriaBatchItem.cs +++ b/src/NHibernate/Multi/CriteriaBatchItem.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using NHibernate.Engine; using NHibernate.Impl; +using NHibernate.Loader; using NHibernate.Loader.Criteria; using NHibernate.Persister.Entity; @@ -36,7 +37,7 @@ protected override List GetQueryInformation(ISessionImplementor sessi Session.EnabledFilters ); - list.Add(new QueryInfo(loader.Translator.GetQueryParameters(), loader, loader.QuerySpaces, session)); + list.Add(new QueryInfo(loader.Translator.GetQueryParameters(), (ILoader)loader, loader.QuerySpaces, session)); } return list; diff --git a/src/NHibernate/Multi/QueryBatchItem.cs b/src/NHibernate/Multi/QueryBatchItem.cs index 71de6a2a4ae..19fe4a37279 100644 --- a/src/NHibernate/Multi/QueryBatchItem.cs +++ b/src/NHibernate/Multi/QueryBatchItem.cs @@ -24,7 +24,7 @@ protected override List GetQueryInformation(ISessionImplementor sessi return Query .GetTranslators(Session, queryParameters) - .Select(t => new QueryInfo(queryParameters, t.Loader, new HashSet(t.QuerySpaces), session)) + .Select(t => new QueryInfo(queryParameters, t.GetQueryLoader(), new HashSet(t.QuerySpaces), session)) .ToList(); } diff --git a/src/NHibernate/Multi/QueryBatchItemBase.cs b/src/NHibernate/Multi/QueryBatchItemBase.cs index 7920e291c73..3b080f36c0a 100644 --- a/src/NHibernate/Multi/QueryBatchItemBase.cs +++ b/src/NHibernate/Multi/QueryBatchItemBase.cs @@ -5,6 +5,7 @@ using System.Linq; using NHibernate.Cache; using NHibernate.Engine; +using NHibernate.Loader; using NHibernate.SqlCommand; using NHibernate.Type; using NHibernate.Util; @@ -28,11 +29,14 @@ public abstract partial class QueryBatchItemBase : IQueryBatchItem QueryLoader as Loader.Loader ?? throw new NotSupportedException("Custom loader is not supported."); + /// /// The query loader. /// - public Loader.Loader Loader { get; set; } + public ILoader QueryLoader { get; } /// /// The query result. @@ -59,13 +63,13 @@ protected class QueryInfo : ICachingInformation, ICachingInformationWithFetches // Do not store but forward instead: Loader.ResultTypes can be null initially (if AutoDiscoverTypes // is enabled). /// - public IType[] ResultTypes => Loader.ResultTypes; + public IType[] ResultTypes => QueryLoader.ResultTypes; /// - public IType[] CacheTypes => Loader.CacheTypes; + public IType[] CacheTypes => QueryLoader.CacheTypes; /// - public string QueryIdentifier => Loader.QueryIdentifier; + public string QueryIdentifier => QueryLoader.QueryIdentifier; /// public IList ResultToCache { get; set; } @@ -85,8 +89,6 @@ protected class QueryInfo : ICachingInformation, ICachingInformationWithFetches /// public CacheBatcher CacheBatcher { get; private set; } - // 6.0 TODO : remove - /// /// Create a new QueryInfo. /// @@ -94,19 +96,34 @@ protected class QueryInfo : ICachingInformation, ICachingInformationWithFetches /// The loader. /// The query spaces. /// The session of the query. + // Since 5.5. + [Obsolete("Use overload taking an ILoader instead.")] public QueryInfo( QueryParameters parameters, Loader.Loader loader, ISet querySpaces, + ISessionImplementor session) : this(parameters, (ILoader)loader, querySpaces, session) + { + } + + /// + /// Create a new QueryInfo. + /// + /// The query parameters. + /// The loader. + /// The query spaces. + /// The session of the query. + public QueryInfo( + QueryParameters parameters, ILoader loader, ISet querySpaces, ISessionImplementor session) { Parameters = parameters; - Loader = loader; + QueryLoader = loader; QuerySpaces = querySpaces; IsCacheable = loader.IsCacheable(parameters); if (!IsCacheable) return; - CacheKey = Loader.GenerateQueryKey(session, Parameters); + CacheKey = QueryLoader.GenerateQueryKey(session, Parameters); CanGetFromCache = Parameters.CanGetFromCache(session); CanPutToCache = Parameters.CanPutToCache(session); } @@ -172,7 +189,7 @@ public IEnumerable GetCommands() if (qi.IsResultFromCache) continue; - yield return qi.Loader.CreateSqlCommand(qi.Parameters, Session); + yield return qi.QueryLoader.CreateSqlCommand(qi.Parameters, Session); } } @@ -191,7 +208,7 @@ public int ProcessResultsSet(DbDataReader reader) for (var i = 0; i < _queryInfos.Count; i++) { var queryInfo = _queryInfos[i]; - var loader = queryInfo.Loader; + var loader = queryInfo.QueryLoader; var queryParameters = queryInfo.Parameters; //Skip processing for items already loaded from cache @@ -298,20 +315,20 @@ public void ProcessResults() var queryInfo = _queryInfos[i]; if (_subselectResultKeys[i] != null) { - queryInfo.Loader.CreateSubselects(_subselectResultKeys[i], queryInfo.Parameters, Session); + queryInfo.QueryLoader.CreateSubselects(_subselectResultKeys[i], queryInfo.Parameters, Session); } if (queryInfo.IsCacheable) { if (queryInfo.IsResultFromCache) { - var queryCacheBuilder = new QueryCacheResultBuilder(queryInfo.Loader); + var queryCacheBuilder = new QueryCacheResultBuilder(queryInfo.QueryLoader); queryInfo.Result = queryCacheBuilder.GetResultList(queryInfo.Result); } // This transformation must not be applied to ResultToCache. queryInfo.Result = - queryInfo.Loader.TransformCacheableResults( + queryInfo.QueryLoader.TransformCacheableResults( queryInfo.Parameters, queryInfo.CacheKey.ResultTransformer, queryInfo.Result); } } @@ -337,7 +354,7 @@ protected List GetTypedResults() var results = new List(_queryInfos.Sum(qi => qi.Result.Count)); foreach (var queryInfo in _queryInfos) { - var list = queryInfo.Loader.GetResultList( + var list = queryInfo.QueryLoader.GetResultList( queryInfo.Result, queryInfo.Parameters.ResultTransformer); ArrayHelper.AddAll(results, list); @@ -364,7 +381,7 @@ private void InitializeEntitiesAndCollections(DbDataReader reader, List[ var queryInfo = _queryInfos[i]; if (queryInfo.IsResultFromCache) continue; - queryInfo.Loader.InitializeEntitiesAndCollections( + queryInfo.QueryLoader.InitializeEntitiesAndCollections( hydratedObjects[i], reader, Session, queryInfo.Parameters.IsReadOnly(Session), queryInfo.CacheBatcher); } @@ -377,7 +394,7 @@ private void StopLoadingCollections(DbDataReader reader) var queryInfo = _queryInfos[i]; if (queryInfo.IsResultFromCache) continue; - queryInfo.Loader.StopLoadingCollections(Session, reader); + queryInfo.QueryLoader.StopLoadingCollections(Session, reader); } } From fc918a71405382ac1223461f00e999dd2ab22aac Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 1 Jan 2023 16:13:47 +0000 Subject: [PATCH 12/19] Generate async files --- .../Hql/Ast/ANTLR/QueryTranslatorImpl.cs | 2 +- src/NHibernate/Async/Hql/IQueryTranslator.cs | 1 + src/NHibernate/Async/Impl/MultiQueryImpl.cs | 20 +++++++++---------- .../Async/Multi/CriteriaBatchItem.cs | 1 + .../Async/Multi/QueryBatchItemBase.cs | 1 + 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/NHibernate/Async/Hql/Ast/ANTLR/QueryTranslatorImpl.cs b/src/NHibernate/Async/Hql/Ast/ANTLR/QueryTranslatorImpl.cs index 662e36424aa..67ce030991e 100644 --- a/src/NHibernate/Async/Hql/Ast/ANTLR/QueryTranslatorImpl.cs +++ b/src/NHibernate/Async/Hql/Ast/ANTLR/QueryTranslatorImpl.cs @@ -34,7 +34,7 @@ namespace NHibernate.Hql.Ast.ANTLR { using System.Threading.Tasks; using System.Threading; - public partial class QueryTranslatorImpl : IFilterTranslator + public partial class QueryTranslatorImpl : IFilterTranslator, IQueryTranslatorWithCustomizableLoader { public async Task ListAsync(ISessionImplementor session, QueryParameters queryParameters, CancellationToken cancellationToken) diff --git a/src/NHibernate/Async/Hql/IQueryTranslator.cs b/src/NHibernate/Async/Hql/IQueryTranslator.cs index dc20147ba64..4156b40ec1c 100644 --- a/src/NHibernate/Async/Hql/IQueryTranslator.cs +++ b/src/NHibernate/Async/Hql/IQueryTranslator.cs @@ -8,6 +8,7 @@ //------------------------------------------------------------------------------ +using System; using System.Collections; using System.Collections.Generic; using NHibernate.Engine; diff --git a/src/NHibernate/Async/Impl/MultiQueryImpl.cs b/src/NHibernate/Async/Impl/MultiQueryImpl.cs index 5d5d3ed7377..3ecc5e5b933 100644 --- a/src/NHibernate/Async/Impl/MultiQueryImpl.cs +++ b/src/NHibernate/Async/Impl/MultiQueryImpl.cs @@ -103,29 +103,28 @@ protected async Task> DoListAsync(CancellationToken cancellationTok { ITranslator translator = Translators[i]; QueryParameters parameter = Parameters[i]; - var loader = translator.GetQueryLoader(); - int entitySpan = loader.EntityPersisters.Length; + int entitySpan = translator.Loader.EntityPersisters.Length; hydratedObjects[i] = entitySpan > 0 ? new List() : null; RowSelection selection = parameter.RowSelection; int maxRows = Loader.Loader.HasMaxRows(selection) ? selection.MaxRows : int.MaxValue; - if (!dialect.SupportsLimitOffset || !loader.UseLimit(selection, dialect)) + if (!dialect.SupportsLimitOffset || !translator.Loader.UseLimit(selection, dialect)) { await (Loader.Loader.AdvanceAsync(reader, selection, cancellationToken)).ConfigureAwait(false); } if (parameter.HasAutoDiscoverScalarTypes) { - loader.AutoDiscoverTypes(reader, parameter, null); + translator.Loader.AutoDiscoverTypes(reader, parameter, null); } - LockMode[] lockModeArray = loader.GetLockModes(parameter.LockModes); + LockMode[] lockModeArray = translator.Loader.GetLockModes(parameter.LockModes); EntityKey optionalObjectKey = Loader.Loader.GetOptionalObjectKey(parameter, session); - createSubselects[i] = loader.IsSubselectLoadingEnabled; + createSubselects[i] = translator.Loader.IsSubselectLoadingEnabled; subselectResultKeys[i] = createSubselects[i] ? new List() : null; - loader.HandleEmptyCollections(parameter.CollectionKeys, reader, session); + translator.Loader.HandleEmptyCollections(parameter.CollectionKeys, reader, session); EntityKey[] keys = new EntityKey[entitySpan]; // we can reuse it each time if (log.IsDebugEnabled()) @@ -143,7 +142,7 @@ protected async Task> DoListAsync(CancellationToken cancellationTok } rowCount++; - object result = await (loader.GetRowFromResultSetAsync( + object result = await (translator.Loader.GetRowFromResultSetAsync( reader, session, parameter, lockModeArray, optionalObjectKey, hydratedObjects[i], keys, true, null, null, (persister, data) => cacheBatcher.AddToBatch(persister, data), cancellationToken)).ConfigureAwait(false); tempResults.Add(result); @@ -174,13 +173,12 @@ protected async Task> DoListAsync(CancellationToken cancellationTok { ITranslator translator = translators[i]; QueryParameters parameter = parameters[i]; - var loader = translator.GetQueryLoader(); - await (loader.InitializeEntitiesAndCollectionsAsync(hydratedObjects[i], reader, session, false, cacheBatcher, cancellationToken)).ConfigureAwait(false); + await (translator.Loader.InitializeEntitiesAndCollectionsAsync(hydratedObjects[i], reader, session, false, cacheBatcher, cancellationToken)).ConfigureAwait(false); if (createSubselects[i]) { - loader.CreateSubselects(subselectResultKeys[i], parameter, session); + translator.Loader.CreateSubselects(subselectResultKeys[i], parameter, session); } } diff --git a/src/NHibernate/Async/Multi/CriteriaBatchItem.cs b/src/NHibernate/Async/Multi/CriteriaBatchItem.cs index cc67da2ffb7..73b3268c1a7 100644 --- a/src/NHibernate/Async/Multi/CriteriaBatchItem.cs +++ b/src/NHibernate/Async/Multi/CriteriaBatchItem.cs @@ -12,6 +12,7 @@ using System.Collections.Generic; using NHibernate.Engine; using NHibernate.Impl; +using NHibernate.Loader; using NHibernate.Loader.Criteria; using NHibernate.Persister.Entity; diff --git a/src/NHibernate/Async/Multi/QueryBatchItemBase.cs b/src/NHibernate/Async/Multi/QueryBatchItemBase.cs index 3bce616273d..45285afa8de 100644 --- a/src/NHibernate/Async/Multi/QueryBatchItemBase.cs +++ b/src/NHibernate/Async/Multi/QueryBatchItemBase.cs @@ -15,6 +15,7 @@ using System.Linq; using NHibernate.Cache; using NHibernate.Engine; +using NHibernate.Loader; using NHibernate.SqlCommand; using NHibernate.Type; using NHibernate.Util; From 5b3310427573f417411273f59cf747bf918ffc3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericdelaporte@users.noreply.github.com> Date: Sun, 1 Jan 2023 17:48:00 +0100 Subject: [PATCH 13/19] Revert an undue change --- src/NHibernate/Hql/IFilterTranslator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate/Hql/IFilterTranslator.cs b/src/NHibernate/Hql/IFilterTranslator.cs index 67fc3314352..4916b95e7ac 100644 --- a/src/NHibernate/Hql/IFilterTranslator.cs +++ b/src/NHibernate/Hql/IFilterTranslator.cs @@ -16,4 +16,4 @@ public interface IFilterTranslator : IQueryTranslator /// Does this represent a shallow (scalar or entity-id) select? void Compile(string collectionRole, IDictionary replacements, bool shallow); } -} +} \ No newline at end of file From 6ec4a4568742460062f6fc5868ea9d3b1c80a0fd Mon Sep 17 00:00:00 2001 From: Michael Kaufmann <47595100+micmerchant@users.noreply.github.com> Date: Tue, 3 Jan 2023 10:19:28 +0100 Subject: [PATCH 14/19] Update src/NHibernate/Loader/Hql/QueryLoaderFactory.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Frédéric Delaporte <12201973+fredericDelaporte@users.noreply.github.com> --- src/NHibernate/Loader/Hql/QueryLoaderFactory.cs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/NHibernate/Loader/Hql/QueryLoaderFactory.cs b/src/NHibernate/Loader/Hql/QueryLoaderFactory.cs index 4a9a471e9fe..da82ebe53e7 100644 --- a/src/NHibernate/Loader/Hql/QueryLoaderFactory.cs +++ b/src/NHibernate/Loader/Hql/QueryLoaderFactory.cs @@ -1,13 +1,4 @@ -// Copyright (c) 2022 MOCCA Software GmbH. All rights reserved. -// -// All rights are reserved. Reproduction or transmission in whole or in part, -// any form or by any means, electronic, mechanical or otherwise, is prohibited -// without the prior written consent of the copyright owner. -// -// File Name: QueryLoaderFactory.cs -// Created: 12/12/2022 -// Author: Michael Kaufmann (mika) - +``` using NHibernate.Engine; using NHibernate.Hql.Ast.ANTLR; using NHibernate.Hql.Ast.ANTLR.Tree; From 6567805008e4a780539ac61ee5688acf9a5de903 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann <47595100+micmerchant@users.noreply.github.com> Date: Tue, 3 Jan 2023 10:19:46 +0100 Subject: [PATCH 15/19] Update src/NHibernate/Persister/IPersister.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Frédéric Delaporte <12201973+fredericDelaporte@users.noreply.github.com> --- src/NHibernate/Persister/IPersister.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate/Persister/IPersister.cs b/src/NHibernate/Persister/IPersister.cs index 43710dd0f62..42cf34b0c21 100644 --- a/src/NHibernate/Persister/IPersister.cs +++ b/src/NHibernate/Persister/IPersister.cs @@ -4,7 +4,7 @@ namespace NHibernate.Persister { - // TODO 6.0: Make this public and make IEntityPersister and ICollectionPersister derive it. + // TODO 6.0: Make IEntityPersister and ICollectionPersister derive it. public interface IPersister { /// From 1f3ac9560c76cc911dacd2089f4c226a4ed40bc0 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Tue, 3 Jan 2023 12:18:10 +0100 Subject: [PATCH 16/19] - adds a future query test - HqlTranslatorWrapper for future queries implements the ITranslatorWithCustomizableLoader now - documentation added for test classes --- .../QueryTranslator/CustomQueryLoader.cs | 4 ++++ .../CustomQueryLoaderFactory.cs | 3 +++ .../CustomQueryLoaderFixture.cs | 20 ++++++++++++++----- .../CustomQueryTranslatorFactory.cs | 1 - src/NHibernate/Impl/MultiQueryImpl.cs | 2 +- .../Loader/Hql/QueryLoaderFactory.cs | 1 - 6 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/NHibernate.Test/QueryTranslator/CustomQueryLoader.cs b/src/NHibernate.Test/QueryTranslator/CustomQueryLoader.cs index 621716c74d6..6d072e01102 100644 --- a/src/NHibernate.Test/QueryTranslator/CustomQueryLoader.cs +++ b/src/NHibernate.Test/QueryTranslator/CustomQueryLoader.cs @@ -16,6 +16,10 @@ namespace NHibernate.Test.QueryTranslator { + /// + /// Custom query loader to test the functionality of custom query translator factory + /// with a custom query loader factory. + /// internal sealed class CustomQueryLoader: IQueryLoader { private readonly IQueryLoader _queryLoader; diff --git a/src/NHibernate.Test/QueryTranslator/CustomQueryLoaderFactory.cs b/src/NHibernate.Test/QueryTranslator/CustomQueryLoaderFactory.cs index ea6d8d6524b..914f16e52eb 100644 --- a/src/NHibernate.Test/QueryTranslator/CustomQueryLoaderFactory.cs +++ b/src/NHibernate.Test/QueryTranslator/CustomQueryLoaderFactory.cs @@ -5,6 +5,9 @@ namespace NHibernate.Test.QueryTranslator { + /// + /// Custom query loader factory to test the functionality of custom query translator factory. + /// internal sealed class CustomQueryLoaderFactory: IQueryLoaderFactory { public IQueryLoader Create( diff --git a/src/NHibernate.Test/QueryTranslator/CustomQueryLoaderFixture.cs b/src/NHibernate.Test/QueryTranslator/CustomQueryLoaderFixture.cs index 3331e402639..24342e8e2a4 100644 --- a/src/NHibernate.Test/QueryTranslator/CustomQueryLoaderFixture.cs +++ b/src/NHibernate.Test/QueryTranslator/CustomQueryLoaderFixture.cs @@ -5,7 +5,7 @@ namespace NHibernate.Test.QueryTranslator { - [TestFixture] + [TestFixture(Description = "Tests a custom query translator factory for all query interfaces.")] internal sealed class CustomQueryLoaderFixture : TestCase { private ISession _session; @@ -66,7 +66,7 @@ protected override void OnTearDown() _session.Dispose(); } - [Test] + [Test(Description = "Tests criteria queries.")] public void CriteriaQueryTest() { var customers = _session.CreateCriteria(typeof(Customer)) @@ -75,7 +75,17 @@ public void CriteriaQueryTest() Assert.AreEqual(1, customers.Count); } - [Test] + [Test(Description = "Tests future queries.")] + public void FutureQueryTest() + { + var customers = _session.CreateQuery("select c from Customer c") + .Future() + .ToList(); + + Assert.AreEqual(1, customers.Count); + } + + [Test(Description = "Tests HQL queries.")] public void HqlQueryTest() { var customers = _session.CreateQuery("select c from Customer c") @@ -84,7 +94,7 @@ public void HqlQueryTest() Assert.AreEqual(1, customers.Count); } - [Test] + [Test(Description = "Tests LINQ queries.")] public void LinqQueryTest() { var customers = _session.Query() @@ -93,7 +103,7 @@ public void LinqQueryTest() Assert.AreEqual(1, customers.Count); } - [Test] + [Test(Description = "Tests query over queries.")] public void QueryOverQueryTest() { var customers = _session.QueryOver() diff --git a/src/NHibernate.Test/QueryTranslator/CustomQueryTranslatorFactory.cs b/src/NHibernate.Test/QueryTranslator/CustomQueryTranslatorFactory.cs index c74907217ed..f918b275753 100644 --- a/src/NHibernate.Test/QueryTranslator/CustomQueryTranslatorFactory.cs +++ b/src/NHibernate.Test/QueryTranslator/CustomQueryTranslatorFactory.cs @@ -4,7 +4,6 @@ using NHibernate.Hql.Ast.ANTLR; using NHibernate.Hql.Ast.ANTLR.Tree; using NHibernate.Linq; -using NHibernate.Loader.Hql; using NHibernate.Type; namespace NHibernate.Test.QueryTranslator diff --git a/src/NHibernate/Impl/MultiQueryImpl.cs b/src/NHibernate/Impl/MultiQueryImpl.cs index 90c905501ef..7191196fd74 100644 --- a/src/NHibernate/Impl/MultiQueryImpl.cs +++ b/src/NHibernate/Impl/MultiQueryImpl.cs @@ -857,7 +857,7 @@ public static ILoader GetQueryLoader(this ITranslator translator) } } - internal class HqlTranslatorWrapper : ITranslator + internal class HqlTranslatorWrapper : ITranslatorWithCustomizableLoader { private readonly IQueryTranslator innerTranslator; diff --git a/src/NHibernate/Loader/Hql/QueryLoaderFactory.cs b/src/NHibernate/Loader/Hql/QueryLoaderFactory.cs index da82ebe53e7..6b5b7c57318 100644 --- a/src/NHibernate/Loader/Hql/QueryLoaderFactory.cs +++ b/src/NHibernate/Loader/Hql/QueryLoaderFactory.cs @@ -1,4 +1,3 @@ -``` using NHibernate.Engine; using NHibernate.Hql.Ast.ANTLR; using NHibernate.Hql.Ast.ANTLR.Tree; From d219fdfeeb0907fa2d0ee36b9512e15284a69b29 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Tue, 3 Jan 2023 12:20:08 +0100 Subject: [PATCH 17/19] - async code generated --- .../Async/QueryTranslator/CustomQueryLoaderFixture.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/NHibernate.Test/Async/QueryTranslator/CustomQueryLoaderFixture.cs b/src/NHibernate.Test/Async/QueryTranslator/CustomQueryLoaderFixture.cs index 7f3b251feb8..b56cc97a008 100644 --- a/src/NHibernate.Test/Async/QueryTranslator/CustomQueryLoaderFixture.cs +++ b/src/NHibernate.Test/Async/QueryTranslator/CustomQueryLoaderFixture.cs @@ -17,7 +17,7 @@ namespace NHibernate.Test.QueryTranslator { using System.Threading.Tasks; - [TestFixture] + [TestFixture(Description = "Tests a custom query translator factory for all query interfaces.")] internal sealed class CustomQueryLoaderFixtureAsync : TestCase { private ISession _session; @@ -78,7 +78,7 @@ protected override void OnTearDown() _session.Dispose(); } - [Test] + [Test(Description = "Tests criteria queries.")] public async Task CriteriaQueryTestAsync() { var customers = await (_session.CreateCriteria(typeof(Customer)) @@ -87,7 +87,7 @@ public async Task CriteriaQueryTestAsync() Assert.AreEqual(1, customers.Count); } - [Test] + [Test(Description = "Tests HQL queries.")] public async Task HqlQueryTestAsync() { var customers = await (_session.CreateQuery("select c from Customer c") @@ -96,7 +96,7 @@ public async Task HqlQueryTestAsync() Assert.AreEqual(1, customers.Count); } - [Test] + [Test(Description = "Tests LINQ queries.")] public async Task LinqQueryTestAsync() { var customers = await (_session.Query() @@ -105,7 +105,7 @@ public async Task LinqQueryTestAsync() Assert.AreEqual(1, customers.Count); } - [Test] + [Test(Description = "Tests query over queries.")] public async Task QueryOverQueryTestAsync() { var customers = await (_session.QueryOver() From 2c8bcc6e2c2acacff30e0470a1c638556d431812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericdelaporte@users.noreply.github.com> Date: Sun, 8 Jan 2023 18:43:03 +0100 Subject: [PATCH 18/19] Implement the transitional interface on each translator And adjust the tests. --- .../CustomQueryLoaderFixture.cs | 95 ++++++++++--------- src/NHibernate/Impl/MultiQueryImpl.cs | 8 +- 2 files changed, 57 insertions(+), 46 deletions(-) diff --git a/src/NHibernate.Test/QueryTranslator/CustomQueryLoaderFixture.cs b/src/NHibernate.Test/QueryTranslator/CustomQueryLoaderFixture.cs index 24342e8e2a4..a2d353e0988 100644 --- a/src/NHibernate.Test/QueryTranslator/CustomQueryLoaderFixture.cs +++ b/src/NHibernate.Test/QueryTranslator/CustomQueryLoaderFixture.cs @@ -11,26 +11,27 @@ internal sealed class CustomQueryLoaderFixture : TestCase private ISession _session; private ITransaction _transaction; - protected override string[] Mappings => new[] - { - "Northwind.Mappings.Customer.hbm.xml", - "Northwind.Mappings.Employee.hbm.xml", - "Northwind.Mappings.Order.hbm.xml", - "Northwind.Mappings.OrderLine.hbm.xml", - "Northwind.Mappings.Product.hbm.xml", - "Northwind.Mappings.ProductCategory.hbm.xml", - "Northwind.Mappings.Region.hbm.xml", - "Northwind.Mappings.Shipper.hbm.xml", - "Northwind.Mappings.Supplier.hbm.xml", - "Northwind.Mappings.Territory.hbm.xml", - "Northwind.Mappings.AnotherEntity.hbm.xml", - "Northwind.Mappings.Role.hbm.xml", - "Northwind.Mappings.User.hbm.xml", - "Northwind.Mappings.TimeSheet.hbm.xml", - "Northwind.Mappings.Animal.hbm.xml", - "Northwind.Mappings.Patient.hbm.xml", - "Northwind.Mappings.NumericEntity.hbm.xml" - }; + protected override string[] Mappings => + new[] + { + "Northwind.Mappings.Customer.hbm.xml", + "Northwind.Mappings.Employee.hbm.xml", + "Northwind.Mappings.Order.hbm.xml", + "Northwind.Mappings.OrderLine.hbm.xml", + "Northwind.Mappings.Product.hbm.xml", + "Northwind.Mappings.ProductCategory.hbm.xml", + "Northwind.Mappings.Region.hbm.xml", + "Northwind.Mappings.Shipper.hbm.xml", + "Northwind.Mappings.Supplier.hbm.xml", + "Northwind.Mappings.Territory.hbm.xml", + "Northwind.Mappings.AnotherEntity.hbm.xml", + "Northwind.Mappings.Role.hbm.xml", + "Northwind.Mappings.User.hbm.xml", + "Northwind.Mappings.TimeSheet.hbm.xml", + "Northwind.Mappings.Animal.hbm.xml", + "Northwind.Mappings.Patient.hbm.xml", + "Northwind.Mappings.NumericEntity.hbm.xml" + }; protected override string MappingsAssembly => "NHibernate.DomainModel"; @@ -42,15 +43,15 @@ protected override void Configure(Configuration configuration) protected override void OnSetUp() { base.OnSetUp(); - + _session = OpenSession(); _transaction = _session.BeginTransaction(); var customer = new Customer - { - CustomerId = "C1", - CompanyName = "Company" - }; + { + CustomerId = "C1", + CompanyName = "Company" + }; _session.Save(customer); _session.Flush(); _session.Clear(); @@ -59,7 +60,7 @@ protected override void OnSetUp() protected override void OnTearDown() { base.OnTearDown(); - + _transaction.Rollback(); _transaction.Dispose(); _session.Close(); @@ -70,46 +71,50 @@ protected override void OnTearDown() public void CriteriaQueryTest() { var customers = _session.CreateCriteria(typeof(Customer)) - .List(); - - Assert.AreEqual(1, customers.Count); + .List(); + + Assert.That(customers.Count, Is.EqualTo(1)); } - + [Test(Description = "Tests future queries.")] public void FutureQueryTest() { - var customers = _session.CreateQuery("select c from Customer c") - .Future() - .ToList(); - - Assert.AreEqual(1, customers.Count); + var futureCustomers = _session + .CreateQuery("select c from Customer c") + .Future(); + var futureCustomersCount = _session + .CreateQuery("select count(*) from Customer c") + .FutureValue(); + + Assert.That(futureCustomersCount.Value, Is.EqualTo(1)); + Assert.That(futureCustomers.ToList().Count, Is.EqualTo(futureCustomersCount.Value)); } - + [Test(Description = "Tests HQL queries.")] public void HqlQueryTest() { var customers = _session.CreateQuery("select c from Customer c") - .List(); - - Assert.AreEqual(1, customers.Count); + .List(); + + Assert.That(customers.Count, Is.EqualTo(1)); } [Test(Description = "Tests LINQ queries.")] public void LinqQueryTest() { var customers = _session.Query() - .ToList(); - - Assert.AreEqual(1, customers.Count); + .ToList(); + + Assert.That(customers.Count, Is.EqualTo(1)); } [Test(Description = "Tests query over queries.")] public void QueryOverQueryTest() { var customers = _session.QueryOver() - .List(); - - Assert.AreEqual(1, customers.Count); + .List(); + + Assert.That(customers.Count, Is.EqualTo(1)); } } } diff --git a/src/NHibernate/Impl/MultiQueryImpl.cs b/src/NHibernate/Impl/MultiQueryImpl.cs index 7191196fd74..6affa8061f1 100644 --- a/src/NHibernate/Impl/MultiQueryImpl.cs +++ b/src/NHibernate/Impl/MultiQueryImpl.cs @@ -866,6 +866,7 @@ public HqlTranslatorWrapper(IQueryTranslator translator) innerTranslator = translator; } + // Since 5.5. [Obsolete("Use QueryLoader instead.")] public Loader.Loader Loader { @@ -891,7 +892,7 @@ public string[] ReturnAliases } } - internal class SqlTranslator : ITranslator + internal class SqlTranslator : ITranslatorWithCustomizableLoader { private readonly CustomLoader loader; @@ -908,11 +909,16 @@ public IType[] ReturnTypes get { return loader.ResultTypes; } } + // Since 5.5. + [Obsolete("Use QueryLoader instead.")] public Loader.Loader Loader { get { return loader; } } + /// + public ILoader QueryLoader => loader; + public ICollection QuerySpaces { get { return loader.QuerySpaces; } From 6e1626dcfc010b02902a4e42ccaf9c9b1a109505 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 8 Jan 2023 17:46:39 +0000 Subject: [PATCH 19/19] Generate async files --- .../CustomQueryLoaderFixture.cs | 93 +++++++++++-------- 1 file changed, 54 insertions(+), 39 deletions(-) diff --git a/src/NHibernate.Test/Async/QueryTranslator/CustomQueryLoaderFixture.cs b/src/NHibernate.Test/Async/QueryTranslator/CustomQueryLoaderFixture.cs index b56cc97a008..67d15ddb2b4 100644 --- a/src/NHibernate.Test/Async/QueryTranslator/CustomQueryLoaderFixture.cs +++ b/src/NHibernate.Test/Async/QueryTranslator/CustomQueryLoaderFixture.cs @@ -23,26 +23,27 @@ internal sealed class CustomQueryLoaderFixtureAsync : TestCase private ISession _session; private ITransaction _transaction; - protected override string[] Mappings => new[] - { - "Northwind.Mappings.Customer.hbm.xml", - "Northwind.Mappings.Employee.hbm.xml", - "Northwind.Mappings.Order.hbm.xml", - "Northwind.Mappings.OrderLine.hbm.xml", - "Northwind.Mappings.Product.hbm.xml", - "Northwind.Mappings.ProductCategory.hbm.xml", - "Northwind.Mappings.Region.hbm.xml", - "Northwind.Mappings.Shipper.hbm.xml", - "Northwind.Mappings.Supplier.hbm.xml", - "Northwind.Mappings.Territory.hbm.xml", - "Northwind.Mappings.AnotherEntity.hbm.xml", - "Northwind.Mappings.Role.hbm.xml", - "Northwind.Mappings.User.hbm.xml", - "Northwind.Mappings.TimeSheet.hbm.xml", - "Northwind.Mappings.Animal.hbm.xml", - "Northwind.Mappings.Patient.hbm.xml", - "Northwind.Mappings.NumericEntity.hbm.xml" - }; + protected override string[] Mappings => + new[] + { + "Northwind.Mappings.Customer.hbm.xml", + "Northwind.Mappings.Employee.hbm.xml", + "Northwind.Mappings.Order.hbm.xml", + "Northwind.Mappings.OrderLine.hbm.xml", + "Northwind.Mappings.Product.hbm.xml", + "Northwind.Mappings.ProductCategory.hbm.xml", + "Northwind.Mappings.Region.hbm.xml", + "Northwind.Mappings.Shipper.hbm.xml", + "Northwind.Mappings.Supplier.hbm.xml", + "Northwind.Mappings.Territory.hbm.xml", + "Northwind.Mappings.AnotherEntity.hbm.xml", + "Northwind.Mappings.Role.hbm.xml", + "Northwind.Mappings.User.hbm.xml", + "Northwind.Mappings.TimeSheet.hbm.xml", + "Northwind.Mappings.Animal.hbm.xml", + "Northwind.Mappings.Patient.hbm.xml", + "Northwind.Mappings.NumericEntity.hbm.xml" + }; protected override string MappingsAssembly => "NHibernate.DomainModel"; @@ -54,15 +55,15 @@ protected override void Configure(Configuration configuration) protected override void OnSetUp() { base.OnSetUp(); - + _session = OpenSession(); _transaction = _session.BeginTransaction(); var customer = new Customer - { - CustomerId = "C1", - CompanyName = "Company" - }; + { + CustomerId = "C1", + CompanyName = "Company" + }; _session.Save(customer); _session.Flush(); _session.Clear(); @@ -71,7 +72,7 @@ protected override void OnSetUp() protected override void OnTearDown() { base.OnTearDown(); - + _transaction.Rollback(); _transaction.Dispose(); _session.Close(); @@ -82,36 +83,50 @@ protected override void OnTearDown() public async Task CriteriaQueryTestAsync() { var customers = await (_session.CreateCriteria(typeof(Customer)) - .ListAsync()); - - Assert.AreEqual(1, customers.Count); + .ListAsync()); + + Assert.That(customers.Count, Is.EqualTo(1)); } - + + [Test(Description = "Tests future queries.")] + public async Task FutureQueryTestAsync() + { + var futureCustomers = _session + .CreateQuery("select c from Customer c") + .Future(); + var futureCustomersCount = _session + .CreateQuery("select count(*) from Customer c") + .FutureValue(); + + Assert.That(await (futureCustomersCount.GetValueAsync()), Is.EqualTo(1)); + Assert.That(futureCustomers.ToList().Count, Is.EqualTo(await (futureCustomersCount.GetValueAsync()))); + } + [Test(Description = "Tests HQL queries.")] public async Task HqlQueryTestAsync() { var customers = await (_session.CreateQuery("select c from Customer c") - .ListAsync()); - - Assert.AreEqual(1, customers.Count); + .ListAsync()); + + Assert.That(customers.Count, Is.EqualTo(1)); } [Test(Description = "Tests LINQ queries.")] public async Task LinqQueryTestAsync() { var customers = await (_session.Query() - .ToListAsync()); - - Assert.AreEqual(1, customers.Count); + .ToListAsync()); + + Assert.That(customers.Count, Is.EqualTo(1)); } [Test(Description = "Tests query over queries.")] public async Task QueryOverQueryTestAsync() { var customers = await (_session.QueryOver() - .ListAsync()); - - Assert.AreEqual(1, customers.Count); + .ListAsync()); + + Assert.That(customers.Count, Is.EqualTo(1)); } } }