diff --git a/src/NHibernate.Test/Async/Linq/QueryReadOnlyTests.cs b/src/NHibernate.Test/Async/Linq/QueryReadOnlyTests.cs new file mode 100644 index 00000000000..a4f2605d0bc --- /dev/null +++ b/src/NHibernate.Test/Async/Linq/QueryReadOnlyTests.cs @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// +// 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.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.Linq +{ + using System.Threading.Tasks; + [TestFixture] + public class QueryReadOnlyTestsAsync : LinqTestCase + { + [Test] + public async Task CanSetReadOnlyOnLinqQueriesAsync() + { + var result = await ((from e in db.Customers + where e.CompanyName == "Bon app'" + select e).WithOptions(o => o.SetReadOnly(true)).ToListAsync()); + + Assert.That(result.All(x => session.IsReadOnly(x)), Is.True); + } + + [Test] + public async Task CanSetReadOnlyOnLinqPagingQueryAsync() + { + var result = await ((from e in db.Customers + select e).Skip(1).Take(1).WithOptions(o => o.SetReadOnly(true)).ToListAsync()); + + Assert.That(result.All(x => session.IsReadOnly(x)), Is.True); + } + + [Test] + public async Task CanSetReadOnlyBeforeSkipOnLinqOrderedPageQueryAsync() + { + var result = await ((from e in db.Customers + orderby e.CompanyName + select e).WithOptions(o => o.SetReadOnly(true)).Skip(5).Take(5).ToListAsync()); + + Assert.That(result.All(x => session.IsReadOnly(x)), Is.True); + } + } +} diff --git a/src/NHibernate.Test/Linq/QueryReadOnlyTests.cs b/src/NHibernate.Test/Linq/QueryReadOnlyTests.cs new file mode 100644 index 00000000000..6b683d9a4d0 --- /dev/null +++ b/src/NHibernate.Test/Linq/QueryReadOnlyTests.cs @@ -0,0 +1,39 @@ +using System.Linq; +using NHibernate.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.Linq +{ + [TestFixture] + public class QueryReadOnlyTests : LinqTestCase + { + [Test] + public void CanSetReadOnlyOnLinqQueries() + { + var result = (from e in db.Customers + where e.CompanyName == "Bon app'" + select e).WithOptions(o => o.SetReadOnly(true)).ToList(); + + Assert.That(result.All(x => session.IsReadOnly(x)), Is.True); + } + + [Test] + public void CanSetReadOnlyOnLinqPagingQuery() + { + var result = (from e in db.Customers + select e).Skip(1).Take(1).WithOptions(o => o.SetReadOnly(true)).ToList(); + + Assert.That(result.All(x => session.IsReadOnly(x)), Is.True); + } + + [Test] + public void CanSetReadOnlyBeforeSkipOnLinqOrderedPageQuery() + { + var result = (from e in db.Customers + orderby e.CompanyName + select e).WithOptions(o => o.SetReadOnly(true)).Skip(5).Take(5).ToList(); + + Assert.That(result.All(x => session.IsReadOnly(x)), Is.True); + } + } +} diff --git a/src/NHibernate/Async/Linq/DefaultQueryProvider.cs b/src/NHibernate/Async/Linq/DefaultQueryProvider.cs index c927dea45c3..c0e32a49cb2 100644 --- a/src/NHibernate/Async/Linq/DefaultQueryProvider.cs +++ b/src/NHibernate/Async/Linq/DefaultQueryProvider.cs @@ -69,7 +69,7 @@ public Task ExecuteDmlAsync(QueryMode queryMode, Expression expression, var query = Session.CreateQuery(nhLinqExpression); SetParameters(query, nhLinqExpression.ParameterValuesByName); - ApplyOptions(query); + _options?.Apply(query); return query.ExecuteUpdateAsync(cancellationToken); } catch (Exception ex) diff --git a/src/NHibernate/Linq/DefaultQueryProvider.cs b/src/NHibernate/Linq/DefaultQueryProvider.cs index aacaa9357f8..d43ae5568c4 100644 --- a/src/NHibernate/Linq/DefaultQueryProvider.cs +++ b/src/NHibernate/Linq/DefaultQueryProvider.cs @@ -175,30 +175,12 @@ protected virtual NhLinqExpression PrepareQuery(Expression expression, out IQuer } SetParameters(query, nhLinqExpression.ParameterValuesByName); - ApplyOptions(query); + _options?.Apply(query); SetResultTransformerAndAdditionalCriteria(query, nhLinqExpression, nhLinqExpression.ParameterValuesByName); return nhLinqExpression; } - private void ApplyOptions(IQuery query) - { - if (_options == null) - return; - - if (_options.Timeout.HasValue) - query.SetTimeout(_options.Timeout.Value); - - if (_options.Cacheable.HasValue) - query.SetCacheable(_options.Cacheable.Value); - - if (_options.CacheMode.HasValue) - query.SetCacheMode(_options.CacheMode.Value); - - if (_options.CacheRegion != null) - query.SetCacheRegion(_options.CacheRegion); - } - protected virtual object ExecuteQuery(NhLinqExpression nhLinqExpression, IQuery query, NhLinqExpression nhQuery) { IList results = query.List(); @@ -279,7 +261,7 @@ public int ExecuteDml(QueryMode queryMode, Expression expression) var query = Session.CreateQuery(nhLinqExpression); SetParameters(query, nhLinqExpression.ParameterValuesByName); - ApplyOptions(query); + _options?.Apply(query); return query.ExecuteUpdate(); } } diff --git a/src/NHibernate/Linq/IQueryableOptions.cs b/src/NHibernate/Linq/IQueryableOptions.cs index 45ca5665194..0cff31e2f38 100644 --- a/src/NHibernate/Linq/IQueryableOptions.cs +++ b/src/NHibernate/Linq/IQueryableOptions.cs @@ -1,9 +1,13 @@ +using System; + namespace NHibernate.Linq { // Methods signatures taken from IQuery. /// /// Expose NH queryable options. /// + //Since v5.1 + [Obsolete("Please use NhQueryableOptions instead.")] public interface IQueryableOptions { /// @@ -29,7 +33,7 @@ public interface IQueryableOptions IQueryableOptions SetCacheMode(CacheMode cacheMode); /// - /// The timeout for the underlying ADO query. + /// Set the timeout for the underlying ADO query. /// /// The timeout in seconds. /// (for method chaining). diff --git a/src/NHibernate/Linq/NhQueryableOptions.cs b/src/NHibernate/Linq/NhQueryableOptions.cs index 3a584ced977..4d68636386b 100644 --- a/src/NHibernate/Linq/NhQueryableOptions.cs +++ b/src/NHibernate/Linq/NhQueryableOptions.cs @@ -1,45 +1,134 @@ namespace NHibernate.Linq { - public class NhQueryableOptions: IQueryableOptions + /// + /// Expose NH queryable options. + /// + public class NhQueryableOptions +#pragma warning disable 618 + : IQueryableOptions +#pragma warning restore 618 { - protected internal bool? Cacheable { get; private set; } - protected internal CacheMode? CacheMode{ get; private set; } - protected internal string CacheRegion { get; private set; } - protected internal int? Timeout { get; private set; } + protected bool? Cacheable { get; private set; } + protected CacheMode? CacheMode { get; private set; } + protected string CacheRegion { get; private set; } + protected int? Timeout { get; private set; } + protected bool? ReadOnly { get; private set; } - public IQueryableOptions SetCacheable(bool cacheable) +#pragma warning disable 618 + /// + IQueryableOptions IQueryableOptions.SetCacheable(bool cacheable) => SetCacheable(cacheable); + + /// + IQueryableOptions IQueryableOptions.SetCacheMode(CacheMode cacheMode) => SetCacheMode(cacheMode); + + /// + IQueryableOptions IQueryableOptions.SetCacheRegion(string cacheRegion) => SetCacheRegion(cacheRegion); + + /// + IQueryableOptions IQueryableOptions.SetTimeout(int timeout) => SetTimeout(timeout); +#pragma warning restore 618 + + /// + /// Enable caching of this query result set. + /// + /// Should the query results be cacheable? + /// (for method chaining). + public NhQueryableOptions SetCacheable(bool cacheable) { Cacheable = cacheable; return this; } - public IQueryableOptions SetCacheMode(CacheMode cacheMode) + /// + /// Override the current session cache mode, just for this query. + /// + /// The cache mode to use. + /// (for method chaining). + public NhQueryableOptions SetCacheMode(CacheMode cacheMode) { CacheMode = cacheMode; return this; } - public IQueryableOptions SetCacheRegion(string cacheRegion) + /// + /// Set the name of the cache region. + /// + /// The name of a query cache region, or + /// for the default query cache + /// (for method chaining). + public NhQueryableOptions SetCacheRegion(string cacheRegion) { CacheRegion = cacheRegion; return this; } - public IQueryableOptions SetTimeout(int timeout) + /// + /// Set the timeout for the underlying ADO query. + /// + /// The timeout in seconds. + /// (for method chaining). + public NhQueryableOptions SetTimeout(int timeout) { Timeout = timeout; return this; } - internal NhQueryableOptions Clone() + /// + /// Set the read-only mode for entities (and proxies) loaded by this query. This setting + /// overrides the default setting for the session (see ). + /// + /// + /// + /// Read-only entities can be modified, but changes are not persisted. They are not + /// dirty-checked and snapshots of persistent state are not maintained. + /// + /// + /// When a proxy is initialized, the loaded entity will have the same read-only setting + /// as the uninitialized proxy, regardless of the session's current setting. + /// + /// + /// The read-only setting has no impact on entities or proxies returned by the criteria + /// that existed in the session before the criteria was executed. + /// + /// + /// + /// If true, entities (and proxies) loaded by the query will be read-only. + /// + /// this (for method chaining) + public NhQueryableOptions SetReadOnly(bool readOnly) + { + ReadOnly = readOnly; + return this; + } + + protected internal NhQueryableOptions Clone() { return new NhQueryableOptions { Cacheable = Cacheable, CacheMode = CacheMode, CacheRegion = CacheRegion, - Timeout = Timeout + Timeout = Timeout, + ReadOnly = ReadOnly }; } + + protected internal void Apply(IQuery query) + { + if (Timeout.HasValue) + query.SetTimeout(Timeout.Value); + + if (Cacheable.HasValue) + query.SetCacheable(Cacheable.Value); + + if (CacheMode.HasValue) + query.SetCacheMode(CacheMode.Value); + + if (CacheRegion != null) + query.SetCacheRegion(CacheRegion); + + if (ReadOnly.HasValue) + query.SetReadOnly(ReadOnly.Value); + } } }