diff --git a/src/NHibernate.Test/Async/QueryTranslator/CustomQueryLoaderFixture.cs b/src/NHibernate.Test/Async/QueryTranslator/CustomQueryLoaderFixture.cs new file mode 100644 index 00000000000..67d15ddb2b4 --- /dev/null +++ b/src/NHibernate.Test/Async/QueryTranslator/CustomQueryLoaderFixture.cs @@ -0,0 +1,132 @@ +//------------------------------------------------------------------------------ +// +// 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(Description = "Tests a custom query translator factory for all query interfaces.")] + 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(Description = "Tests criteria queries.")] + public async Task CriteriaQueryTestAsync() + { + var customers = await (_session.CreateCriteria(typeof(Customer)) + .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.That(customers.Count, Is.EqualTo(1)); + } + + [Test(Description = "Tests LINQ queries.")] + public async Task LinqQueryTestAsync() + { + var customers = await (_session.Query() + .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.That(customers.Count, Is.EqualTo(1)); + } + } +} diff --git a/src/NHibernate.Test/BulkManipulation/BaseFixture.cs b/src/NHibernate.Test/BulkManipulation/BaseFixture.cs index 964e71dfb64..4ef6ae63bd8 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,7 +37,11 @@ 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, + new QueryLoaderFactory()); qt.Compile(null, false); return qt.SQLString; } diff --git a/src/NHibernate.Test/Hql/Ast/BaseFixture.cs b/src/NHibernate.Test/Hql/Ast/BaseFixture.cs index cd12d32802b..a44ddd43a3a 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,7 +42,11 @@ 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, + new QueryLoaderFactory()); qt.Compile(replacements, false); return qt.SQLString; } diff --git a/src/NHibernate.Test/NHSpecificTest/NH2031/HqlModFuctionForMsSqlTest.cs b/src/NHibernate.Test/NHSpecificTest/NH2031/HqlModFuctionForMsSqlTest.cs index 93f45581b30..fa76e0aa034 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,7 +30,11 @@ 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, + new QueryLoaderFactory()); qt.Compile(null, false); return qt.SQLString; } diff --git a/src/NHibernate.Test/QueryTranslator/CustomQueryLoader.cs b/src/NHibernate.Test/QueryTranslator/CustomQueryLoader.cs new file mode 100644 index 00000000000..6d072e01102 --- /dev/null +++ b/src/NHibernate.Test/QueryTranslator/CustomQueryLoader.cs @@ -0,0 +1,206 @@ +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 +{ + /// + /// 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; + + 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..914f16e52eb --- /dev/null +++ b/src/NHibernate.Test/QueryTranslator/CustomQueryLoaderFactory.cs @@ -0,0 +1,23 @@ +using NHibernate.Engine; +using NHibernate.Hql.Ast.ANTLR; +using NHibernate.Hql.Ast.ANTLR.Tree; +using NHibernate.Loader.Hql; + +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( + 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..a2d353e0988 --- /dev/null +++ b/src/NHibernate.Test/QueryTranslator/CustomQueryLoaderFixture.cs @@ -0,0 +1,120 @@ +using System.Linq; +using NHibernate.Cfg; +using NHibernate.DomainModel.Northwind.Entities; +using NUnit.Framework; + +namespace NHibernate.Test.QueryTranslator +{ + [TestFixture(Description = "Tests a custom query translator factory for all query interfaces.")] + 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(Description = "Tests criteria queries.")] + public void CriteriaQueryTest() + { + var customers = _session.CreateCriteria(typeof(Customer)) + .List(); + + Assert.That(customers.Count, Is.EqualTo(1)); + } + + [Test(Description = "Tests future queries.")] + public void FutureQueryTest() + { + 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.That(customers.Count, Is.EqualTo(1)); + } + + [Test(Description = "Tests LINQ queries.")] + public void LinqQueryTest() + { + var customers = _session.Query() + .ToList(); + + Assert.That(customers.Count, Is.EqualTo(1)); + } + + [Test(Description = "Tests query over queries.")] + public void QueryOverQueryTest() + { + var customers = _session.QueryOver() + .List(); + + Assert.That(customers.Count, Is.EqualTo(1)); + } + } +} diff --git a/src/NHibernate.Test/QueryTranslator/CustomQueryTranslatorFactory.cs b/src/NHibernate.Test/QueryTranslator/CustomQueryTranslatorFactory.cs new file mode 100644 index 00000000000..f918b275753 --- /dev/null +++ b/src/NHibernate.Test/QueryTranslator/CustomQueryTranslatorFactory.cs @@ -0,0 +1,82 @@ +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.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); + } + } +} diff --git a/src/NHibernate/Async/Hql/Ast/ANTLR/QueryTranslatorImpl.cs b/src/NHibernate/Async/Hql/Ast/ANTLR/QueryTranslatorImpl.cs index 9a34ba265f4..67ce030991e 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; @@ -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 fd11e81d03b..4156b40ec1c 100644 --- a/src/NHibernate/Async/Hql/IQueryTranslator.cs +++ b/src/NHibernate/Async/Hql/IQueryTranslator.cs @@ -8,11 +8,13 @@ //------------------------------------------------------------------------------ +using System; using System.Collections; using System.Collections.Generic; 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..a7153ea131b 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,13 @@ 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,8 +342,11 @@ private async Task DoQueryAsync(ISessionImplementor session, QueryParamet } } - internal async Task InitializeEntitiesAndCollectionsAsync( - IList hydratedObjects, DbDataReader reader, ISessionImplementor session, bool readOnly, + public async Task InitializeEntitiesAndCollectionsAsync( + IList hydratedObjects, + DbDataReader reader, + ISessionImplementor session, + bool readOnly, CacheBatcher cacheBatcher, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); 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 e590cc77f6f..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; @@ -42,7 +43,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 +151,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 +189,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/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..3607a4c9da7 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,17 @@ public sealed class QueryCacheResultBuilder private readonly IType[] _resultTypes; private readonly Loader.Loader.QueryCacheInfo _cacheInfo; + // 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; } - 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..c2b8cd9e1f6 100644 --- a/src/NHibernate/Engine/Query/QueryPlanCache.cs +++ b/src/NHibernate/Engine/Query/QueryPlanCache.cs @@ -88,7 +88,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 +98,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 +110,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..b6e4e7c2c36 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 @@ -32,9 +33,18 @@ static IQueryTranslator[] CreateQueryTranslators( var polymorphicParsers = AstPolymorphicProcessor.Process(ast, factory); var translators = polymorphicParsers - .ToArray(hql => queryExpression is NhLinqExpression linqExpression - ? new QueryTranslatorImpl(queryIdentifier, hql, filters, factory, linqExpression.GetNamedParameterTypes()) - : new QueryTranslatorImpl(queryIdentifier, hql, filters, factory)); + .ToArray(hql => queryExpression is ILinqQueryExpression linqExpression + ? new QueryTranslatorImpl(queryIdentifier, + hql, + filters, + factory, + new QueryLoaderFactory(), + linqExpression.GetNamedParameterTypes()) + : new QueryTranslatorImpl(queryIdentifier, + hql, + filters, + factory, + new QueryLoaderFactory())); foreach (var translator in translators) { diff --git a/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs b/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs index a30e5594c29..bbf6fdfb48d 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; @@ -23,19 +23,20 @@ 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)); private readonly string _queryIdentifier; private readonly IASTNode _stageOneAst; private readonly ISessionFactoryImplementor _factory; + private readonly IQueryLoaderFactory _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,32 @@ 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, IDictionary enabledFilters, ISessionFactoryImplementor factory) - : this(queryIdentifier, parsedQuery, enabledFilters, factory, null) + : 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, + IQueryLoaderFactory queryLoaderFactory) + : this(queryIdentifier, parsedQuery, enabledFilters, factory, queryLoaderFactory, null) { } @@ -64,12 +85,14 @@ public QueryTranslatorImpl( /// The hql query to translate /// Currently enabled filters /// The session factory constructing this translator instance. + /// The query loader factory. /// The named parameters information. - internal QueryTranslatorImpl( + public QueryTranslatorImpl( string queryIdentifier, IASTNode parsedQuery, IDictionary enabledFilters, ISessionFactoryImplementor factory, + IQueryLoaderFactory queryLoaderFactory, IDictionary> namedParameters) { _queryIdentifier = queryIdentifier; @@ -78,6 +101,7 @@ internal QueryTranslatorImpl( _shallowQuery = false; _enabledFilters = enabledFilters; _factory = factory; + _queryLoaderFactory = queryLoaderFactory; _namedParameters = namedParameters; } @@ -192,10 +216,12 @@ private void ErrorIfSelect() } } - public NHibernate.Loader.Loader Loader - { - get { return _queryLoader; } - } + // 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 { @@ -393,7 +419,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.Create(this, _factory, _sqlAst.Walker.SelectClause); } _compiled = true; diff --git a/src/NHibernate/Hql/IQueryTranslator.cs b/src/NHibernate/Hql/IQueryTranslator.cs index b74bcfd2f8e..93fee2aaf80 100644 --- a/src/NHibernate/Hql/IQueryTranslator.cs +++ b/src/NHibernate/Hql/IQueryTranslator.cs @@ -1,8 +1,10 @@ +using System; using System.Collections; using System.Collections.Generic; using NHibernate.Engine; using NHibernate.Engine.Query; using NHibernate.Event; +using NHibernate.Loader; using NHibernate.Type; namespace NHibernate.Hql @@ -113,10 +115,58 @@ public partial interface IQueryTranslator bool IsManipulationStatement { get; } + // 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 120632ab7b1..6affa8061f1 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,13 +803,61 @@ 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; } } - internal class HqlTranslatorWrapper : ITranslator + // 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 : ITranslatorWithCustomizableLoader { private readonly IQueryTranslator innerTranslator; @@ -817,11 +866,16 @@ public HqlTranslatorWrapper(IQueryTranslator translator) innerTranslator = translator; } + // Since 5.5. + [Obsolete("Use QueryLoader instead.")] public Loader.Loader Loader { get { return innerTranslator.Loader; } } + /// + public ILoader QueryLoader => innerTranslator.GetQueryLoader(); + public IType[] ReturnTypes { get { return innerTranslator.ActualReturnTypes; } @@ -838,7 +892,7 @@ public string[] ReturnAliases } } - internal class SqlTranslator : ITranslator + internal class SqlTranslator : ITranslatorWithCustomizableLoader { private readonly CustomLoader loader; @@ -855,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; } 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..d23e5ca0b31 --- /dev/null +++ b/src/NHibernate/Linq/ILinqQueryExpression.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using NHibernate.Type; + +namespace NHibernate.Linq +{ + /// + /// Defines a linq query expression. + /// + 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 04f4d864ea4..a1e28b93481 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, ICacheableQueryExpression { 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/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/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/Hql/QueryLoaderFactory.cs b/src/NHibernate/Loader/Hql/QueryLoaderFactory.cs new file mode 100644 index 00000000000..6b5b7c57318 --- /dev/null +++ b/src/NHibernate/Loader/Hql/QueryLoaderFactory.cs @@ -0,0 +1,24 @@ +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/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..53294db26de 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,13 @@ 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 +607,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,8 +647,11 @@ private IEnumerable CreateSubselects(List keys, Que } } - internal void InitializeEntitiesAndCollections( - IList hydratedObjects, DbDataReader reader, ISessionImplementor session, bool readOnly, + public void InitializeEntitiesAndCollections( + IList hydratedObjects, + DbDataReader reader, + ISessionImplementor session, + bool readOnly, CacheBatcher cacheBatcher) { ICollectionPersister[] collectionPersisters = CollectionPersisters; @@ -724,7 +728,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 +904,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 +1395,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,7 +1567,7 @@ protected internal virtual void AutoDiscoverTypes(DbDataReader rs) AutoDiscoverTypes(rs, new QueryParameters(), null); } - protected internal virtual void AutoDiscoverTypes( + public virtual void AutoDiscoverTypes( DbDataReader rs, QueryParameters queryParameters, IResultTransformer forcedResultTransformer) { throw new AssertionFailure("Auto discover types not supported in this loader"); @@ -1835,12 +1839,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 +1896,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 +1912,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, @@ -1917,7 +1921,7 @@ internal QueryKey GenerateQueryKey(ISessionImplementor session, QueryParameters 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 5a0123650f3..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,10 +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. @@ -58,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; } @@ -91,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); } @@ -169,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); } } @@ -188,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 @@ -295,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); } } @@ -334,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); @@ -361,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); } @@ -374,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); } } diff --git a/src/NHibernate/Persister/IPersister.cs b/src/NHibernate/Persister/IPersister.cs index 6cd5673c2fb..42cf34b0c21 100644 --- a/src/NHibernate/Persister/IPersister.cs +++ b/src/NHibernate/Persister/IPersister.cs @@ -4,8 +4,8 @@ namespace NHibernate.Persister { - // TODO 6.0: Make this public and make IEntityPersister and ICollectionPersister derive it. - internal interface IPersister + // TODO 6.0: Make IEntityPersister and ICollectionPersister derive it. + public interface IPersister { /// /// The unique name of the persister.