Skip to content

NH-2611 - Allow injectable/inheritance of Linq query provider #313

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 22, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 50 additions & 1 deletion src/NHibernate.Test/CfgTest/ConfigurationFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
using System.Xml;
using NHibernate.Cfg;
using NHibernate.DomainModel;
using NHibernate.Engine;
using NHibernate.Linq;
using NHibernate.Tool.hbm2ddl;
using NHibernate.Util;
using NUnit.Framework;
using Environment=NHibernate.Cfg.Environment;
using Environment = NHibernate.Cfg.Environment;

namespace NHibernate.Test.CfgTest
{
Expand Down Expand Up @@ -417,5 +419,52 @@ public void NH1348()
cfg.Configure(xtr);
// No exception expected
}

public class SampleQueryProvider : DefaultQueryProvider
{
public SampleQueryProvider(ISessionImplementor session) : base(session)
{

}
}

[Test]
public void NH2890Standard()
{
var cfg = new Configuration();
cfg.Configure("TestEnbeddedConfig.cfg.xml")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in the file name

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but not mine! :-) I used a file that was already there

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok

.LinqQueryProvider<SampleQueryProvider>()
.SetDefaultAssembly("NHibernate.DomainModel")
.SetDefaultNamespace("NHibernate.DomainModel");

using (var sessionFactory = cfg.BuildSessionFactory())
{
using (var session = sessionFactory.OpenSession())
{
var query = session.Query<NHibernate.DomainModel.A>();
Assert.IsInstanceOf(typeof(SampleQueryProvider), query.Provider);
}
}
}

[Test]
public void NH2890Xml()
{
var cfg = new Configuration();
cfg.Configure("TestEnbeddedConfig.cfg.xml")
.SetDefaultAssembly("NHibernate.DomainModel")
.SetDefaultNamespace("NHibernate.DomainModel");

using (var sessionFactory = cfg.BuildSessionFactory())
{
using (var session = sessionFactory.OpenSession())
{
var query = session.Query<NHibernate.DomainModel.A>();
Assert.IsInstanceOf(typeof(SampleQueryProvider), query.Provider);
}
}

}

}
}
22 changes: 22 additions & 0 deletions src/NHibernate.Test/CfgTest/Loquacious/ConfigurationFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using NHibernate.Driver;
using NHibernate.Exceptions;
using NHibernate.Hql.Ast.ANTLR;
using NHibernate.Linq;
using NHibernate.Type;
using NUnit.Framework;

Expand Down Expand Up @@ -124,5 +125,26 @@ public void UseConnectionStringName()

Assert.That(cfg.Properties[Environment.ConnectionStringName], Is.EqualTo("MyName"));
}

[Test]
public void NH2890Loquacious()
{
var cfg = new Configuration();
cfg.Configure("TestEnbeddedConfig.cfg.xml")
.SetDefaultAssembly("NHibernate.DomainModel")
.SetDefaultNamespace("NHibernate.DomainModel")
.SessionFactory()
.ParsingLinqThrough<NHibernate.Test.CfgTest.ConfigurationFixture.SampleQueryProvider>();

using (var sessionFactory = cfg.BuildSessionFactory())
{
using (var session = sessionFactory.OpenSession())
{
var query = session.Query<NHibernate.DomainModel.A>();
Assert.IsInstanceOf(typeof(NHibernate.Test.CfgTest.ConfigurationFixture.SampleQueryProvider), query.Provider);
}
}
}

}
}
1 change: 1 addition & 0 deletions src/NHibernate.Test/TestEnbeddedConfig.cfg.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
<property name="connection.connection_string">Server=localhost;initial catalog=nhibernate;User Id=;Password=</property>
<property name="query.substitutions">true 1, false 0, yes 1, no 0</property>
<property name="dialect">NHibernate.Dialect.MsSql2000Dialect</property>
<property name="query.linq_provider_class">NHibernate.Test.CfgTest.ConfigurationFixture+SampleQueryProvider, NHibernate.Test</property>
</session-factory>
</hibernate-configuration>
7 changes: 7 additions & 0 deletions src/NHibernate/Cfg/ConfigurationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using NHibernate.Context;
using NHibernate.Engine;
using NHibernate.Hql;
using NHibernate.Linq;
using NHibernate.Linq.Functions;
using NHibernate.Util;

Expand Down Expand Up @@ -46,6 +47,12 @@ public static Configuration HqlQueryTranslator<TQueryTranslator>(this Configurat
return configuration;
}

public static Configuration LinqQueryProvider<TQueryProvider>(this Configuration configuration) where TQueryProvider : INhQueryProvider
{
configuration.SetProperty(Environment.QueryLinqProvider, typeof(TQueryProvider).AssemblyQualifiedName);
return configuration;
}

public static Configuration LinqToHqlGeneratorsRegistry<TLinqToHqlGeneratorsRegistry>(this Configuration configuration) where TLinqToHqlGeneratorsRegistry : ILinqToHqlGeneratorsRegistry
{
configuration.SetProperty(Environment.LinqToHqlGeneratorsRegistry, typeof(TLinqToHqlGeneratorsRegistry).AssemblyQualifiedName);
Expand Down
3 changes: 3 additions & 0 deletions src/NHibernate/Cfg/Environment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ public static string Version
// The classname of the HQL query parser factory
public const string QueryTranslator = "query.factory_class";

// The class name of the LINQ query provider class, implementing from <see cref="INhQueryProvider"/>
public const string QueryLinqProvider = "query.linq_provider_class";

public const string QueryImports = "query.imports";
public const string Hbm2ddlAuto = "hbm2ddl.auto";
public const string Hbm2ddlKeyWords = "hbm2ddl.keywords";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using NHibernate.Bytecode;
using NHibernate.Hql;
using NHibernate.Linq;

namespace NHibernate.Cfg.Loquacious
{
Expand Down Expand Up @@ -53,6 +54,13 @@ public IFluentSessionFactoryConfiguration ParsingHqlThrough<TQueryTranslator>()
return this;
}

public IFluentSessionFactoryConfiguration ParsingLinqThrough<TQueryProvider>()
where TQueryProvider : INhQueryProvider
{
configuration.SetProperty(Environment.QueryLinqProvider, typeof(TQueryProvider).AssemblyQualifiedName);
return this;
}

public IProxyConfiguration Proxy { get; private set; }
public ICollectionFactoryConfiguration GeneratingCollections { get; private set; }
public IMappingsConfiguration Mapping { get; private set; }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using NHibernate.Hql;
using NHibernate.Linq;
namespace NHibernate.Cfg.Loquacious
{
public interface IFluentSessionFactoryConfiguration
Expand Down Expand Up @@ -26,6 +27,7 @@ public interface IFluentSessionFactoryConfiguration
IFluentSessionFactoryConfiguration GenerateStatistics();
IFluentSessionFactoryConfiguration Using(EntityMode entityMode);
IFluentSessionFactoryConfiguration ParsingHqlThrough<TQueryTranslator>() where TQueryTranslator : IQueryTranslatorFactory;
IFluentSessionFactoryConfiguration ParsingLinqThrough<TQueryProvider>() where TQueryProvider : INhQueryProvider;

IProxyConfiguration Proxy { get; }

Expand Down
2 changes: 2 additions & 0 deletions src/NHibernate/Cfg/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ public Settings()

public IQueryTranslatorFactory QueryTranslatorFactory { get; internal set; }

public System.Type LinqQueryProviderType { get; internal set; }

public ISQLExceptionConverter SqlExceptionConverter { get; internal set; }

public bool IsWrapResultSetsEnabled { get; internal set; }
Expand Down
19 changes: 18 additions & 1 deletion src/NHibernate/Cfg/SettingsFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
using System.Collections;
using System.Collections.Generic;
using System.Data;

using NHibernate.AdoNet;
using NHibernate.AdoNet.Util;
using NHibernate.Cache;
using NHibernate.Connection;
using NHibernate.Dialect;
using NHibernate.Exceptions;
using NHibernate.Hql;
using NHibernate.Linq;
using NHibernate.Linq.Functions;
using NHibernate.Linq.Visitors;
using NHibernate.Transaction;
Expand Down Expand Up @@ -137,6 +137,8 @@ public Settings BuildSettings(IDictionary<string, string> properties)

settings.QueryTranslatorFactory = CreateQueryTranslatorFactory(properties);

settings.LinqQueryProviderType = CreateLinqQueryProviderType(properties);

IDictionary<string, string> querySubstitutions = PropertiesHelper.ToDictionary(Environment.QuerySubstitutions,
" ,=;:\n\t\r\f", properties);
if (log.IsInfoEnabled)
Expand Down Expand Up @@ -365,6 +367,21 @@ private static IQueryTranslatorFactory CreateQueryTranslatorFactory(IDictionary<
}
}

private static System.Type CreateLinqQueryProviderType(IDictionary<string, string> properties)
{
string className = PropertiesHelper.GetString(
Environment.QueryLinqProvider, properties, typeof(DefaultQueryProvider).FullName);
log.Info("Query provider: " + className);
try
{
return System.Type.GetType(className, true);
}
catch (Exception cnfe)
{
throw new HibernateException("could not find query provider class: " + className, cnfe);
}
}

private static ITransactionFactory CreateTransactionFactory(IDictionary<string, string> properties)
{
string className = PropertiesHelper.GetString(
Expand Down
6 changes: 3 additions & 3 deletions src/NHibernate/Linq/DefaultQueryProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public interface INhQueryProvider : IQueryProvider

public class DefaultQueryProvider : INhQueryProvider
{
private static readonly MethodInfo CreateQueryMethodDefinition = ReflectionHelper.GetMethodDefinition((DefaultQueryProvider p) => p.CreateQuery<object>(null));
private static readonly MethodInfo CreateQueryMethodDefinition = ReflectionHelper.GetMethodDefinition((INhQueryProvider p) => p.CreateQuery<object>(null));

private readonly WeakReference _session;

Expand Down Expand Up @@ -66,7 +66,7 @@ public virtual object ExecuteFuture(Expression expression)
return ExecuteFutureQuery(nhLinqExpression, query, nhQuery);
}

protected NhLinqExpression PrepareQuery(Expression expression, out IQuery query, out NhLinqExpression nhQuery)
protected virtual NhLinqExpression PrepareQuery(Expression expression, out IQuery query, out NhLinqExpression nhQuery)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this change?

{
var nhLinqExpression = new NhLinqExpression(expression, Session.Factory);

Expand Down Expand Up @@ -161,7 +161,7 @@ private static void SetParameters(IQuery query, IDictionary<string, Tuple<object
}
}

public void SetResultTransformerAndAdditionalCriteria(IQuery query, NhLinqExpression nhExpression, IDictionary<string, Tuple<object, IType>> parameters)
public virtual void SetResultTransformerAndAdditionalCriteria(IQuery query, NhLinqExpression nhExpression, IDictionary<string, Tuple<object, IType>> parameters)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this change?

{
query.SetResultTransformer(nhExpression.ExpressionToHqlTranslationResults.ResultTransformer);

Expand Down
3 changes: 2 additions & 1 deletion src/NHibernate/Linq/NhQueryable.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Linq;
using System.Linq.Expressions;
using NHibernate.Engine;
Expand All @@ -12,7 +13,7 @@ public class NhQueryable<T> : QueryableBase<T>
{
// This constructor is called by our users, create a new IQueryExecutor.
public NhQueryable(ISessionImplementor session)
: base(new DefaultQueryProvider(session))
: base(QueryProviderFactory.CreateQueryProvider(session))
{
}

Expand Down
25 changes: 25 additions & 0 deletions src/NHibernate/Linq/QueryProviderFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
using NHibernate.Engine;

namespace NHibernate.Linq
{
static class QueryProviderFactory
{
/// <summary>
/// Builds a new query provider.
/// </summary>
/// <param name="session">A session.</param>
/// <returns>The new query provider instance.</returns>
public static INhQueryProvider CreateQueryProvider(ISessionImplementor session)
{
if (session.Factory.Settings.LinqQueryProviderType == null)
{
return new DefaultQueryProvider(session);
}
else
{
return Activator.CreateInstance(session.Factory.Settings.LinqQueryProviderType, session) as INhQueryProvider;
}
}
}
}
1 change: 1 addition & 0 deletions src/NHibernate/NHibernate.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@
<Compile Include="Linq\NestedSelects\SelectClauseRewriter.cs" />
<Compile Include="Linq\NestedSelects\ExpressionHolder.cs" />
<Compile Include="Linq\Visitors\IQueryModelRewriterFactory.cs" />
<Compile Include="Linq\QueryProviderFactory.cs" />
<Compile Include="Linq\Visitors\LeftJoinRewriter.cs" />
<Compile Include="Linq\Functions\CompareGenerator.cs" />
<Compile Include="Linq\ExpressionTransformers\SimplifyCompareTransformer.cs" />
Expand Down
1 change: 1 addition & 0 deletions src/NHibernate/nhibernate-configuration.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
<xs:enumeration value="cache.default_expiration" />
<xs:enumeration value="query.substitutions" />
<xs:enumeration value="query.factory_class" />
<xs:enumeration value="query.linq_provider_class" />
<xs:enumeration value="query.imports" />
<xs:enumeration value="hbm2ddl.auto" />
<xs:enumeration value="hbm2ddl.keywords" />
Expand Down