From: <te...@us...> - 2008-08-15 11:25:06
|
Revision: 3705 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3705&view=rev Author: tehlike Date: 2008-08-15 11:25:15 +0000 (Fri, 15 Aug 2008) Log Message: ----------- -Copied Evaluator from Contrib and renamed it to LocalVariableExpressionReducer Modified Paths: -------------- trunk/nhibernate/src/NHibernate.Linq/NHibernate.Linq.csproj trunk/nhibernate/src/NHibernate.Linq/NHibernateQueryProvider.cs trunk/nhibernate/src/NHibernate.Linq/Query.cs trunk/nhibernate/src/NHibernate.Linq/Visitors/LogicalExpressionReducer.cs Added Paths: ----------- trunk/nhibernate/src/NHibernate.Linq/Util/Guard.cs trunk/nhibernate/src/NHibernate.Linq/Visitors/LocalVariableExpressionReducer.cs Modified: trunk/nhibernate/src/NHibernate.Linq/NHibernate.Linq.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Linq/NHibernate.Linq.csproj 2008-08-15 05:37:47 UTC (rev 3704) +++ trunk/nhibernate/src/NHibernate.Linq/NHibernate.Linq.csproj 2008-08-15 11:25:15 UTC (rev 3705) @@ -46,6 +46,7 @@ </ProjectReference> </ItemGroup> <ItemGroup> + <Compile Include="Util\Guard.cs" /> <Compile Include="Visitors\LogicalExpressionReducer.cs" /> <Compile Include="ExpressionVisitor.cs" /> <Compile Include="NHibernateExtensions.cs" /> @@ -53,6 +54,7 @@ <Compile Include="Query.cs" /> <Compile Include="QueryProvider.cs" /> <Compile Include="Util\TypeSystem.cs" /> + <Compile Include="Visitors\LocalVariableExpressionReducer.cs" /> </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <!-- To modify your build process, add your task inside one of the targets below and uncomment it. Modified: trunk/nhibernate/src/NHibernate.Linq/NHibernateQueryProvider.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Linq/NHibernateQueryProvider.cs 2008-08-15 05:37:47 UTC (rev 3704) +++ trunk/nhibernate/src/NHibernate.Linq/NHibernateQueryProvider.cs 2008-08-15 11:25:15 UTC (rev 3705) @@ -1,17 +1,19 @@ using System; -using System.Linq.Expressions; +using NHibernate.Criterion; using NHibernate.Linq.Util; +using Expression=System.Linq.Expressions.Expression; +using NHibernate.Linq.Visitors; namespace NHibernate.Linq { public class NHibernateQueryProvider : QueryProvider { - private readonly ISession _session; + private readonly ISession session; public NHibernateQueryProvider(ISession session) { - if (session == null) throw new ArgumentNullException("session"); - _session = session; + Guard.AgainstNull(session,"session"); + this.session = session; } public override object Execute(Expression expression) @@ -20,9 +22,9 @@ /* iteratively process expression tree here converting to NH tree */ - //expression = Evaluator.PartialEval(expression); - //expression = new BinaryBooleanReducer().Visit(expression); - //expression = AssociationVisitor.RewriteWithAssociations(_session.SessionFactory, expression); + //expression = LocalVariableExpressionReducer.Reduce(expression); + //expression = LogicalExpressionReducer.Reduce(expression); + //expression = AssociationVisitor.RewriteWithAssociations(session.SessionFactory, expression); //expression = CollectionAliasVisitor.AssignCollectionAccessAliases(expression); //expression = new PropertyToMethodVisitor().Visit(expression); //expression = new BinaryExpressionOrderer().Visit(expression); @@ -30,7 +32,7 @@ //once tree is converted to NH tree, pass it to NHibernateQueryTranslator //which will convert the tree to an NHibernate.SqlCommand.SqlString - //NHibernateQueryTranslator translator = new NHibernateQueryTranslator(_session); + //NHibernateQueryTranslator translator = new NHibernateQueryTranslator(session); //return translator.Translate(expression,this.queryOptions); } } Modified: trunk/nhibernate/src/NHibernate.Linq/Query.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Linq/Query.cs 2008-08-15 05:37:47 UTC (rev 3704) +++ trunk/nhibernate/src/NHibernate.Linq/Query.cs 2008-08-15 11:25:15 UTC (rev 3705) @@ -3,6 +3,7 @@ using System.Linq.Expressions; using System.Collections; using System.Collections.Generic; +using NHibernate.Linq.Util; namespace NHibernate.Linq { @@ -16,7 +17,7 @@ public Query(QueryProvider provider) { - if (provider == null) throw new ArgumentNullException("provider"); + Guard.AgainstNull(provider,"provider"); this.provider = provider; this.expression = Expression.Constant(this); @@ -24,9 +25,10 @@ public Query(QueryProvider provider, Expression expression) { - if (provider == null) throw new ArgumentNullException("provider"); - if (expression == null) throw new ArgumentNullException("expression"); + Guard.AgainstNull(provider,"provider"); + Guard.AgainstNull(expression,"expression"); + if (!typeof(IQueryable<T>).IsAssignableFrom(expression.Type)) throw new ArgumentOutOfRangeException("expression"); Added: trunk/nhibernate/src/NHibernate.Linq/Util/Guard.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Linq/Util/Guard.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Linq/Util/Guard.cs 2008-08-15 11:25:15 UTC (rev 3705) @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace NHibernate.Linq.Util +{ + public static class Guard + { + public static void AgainstNull(object obj,string parameterName) + { + if (obj == null) + throw new ArgumentNullException(parameterName); + } + } +} Added: trunk/nhibernate/src/NHibernate.Linq/Visitors/LocalVariableExpressionReducer.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Linq/Visitors/LocalVariableExpressionReducer.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Linq/Visitors/LocalVariableExpressionReducer.cs 2008-08-15 11:25:15 UTC (rev 3705) @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; + +namespace NHibernate.Linq.Visitors +{ + /// <summary> + /// Evaluates the local references before they are translated into sql. + /// </summary> + public static class LocalVariableExpressionReducer + { + /// <summary> + /// Performs evaluation & replacement of independent sub-trees + /// </summary> + /// <param name="expression">The root of the expression tree.</param> + /// <param name="fnCanBeEvaluated">A function that decides whether a given expression node can be part of the local function.</param> + /// <returns>A new tree with sub-trees evaluated and replaced.</returns> + public static Expression Reduce(Expression expression, Func<Expression, bool> fnCanBeEvaluated) + { + return new SubtreeEvaluator(new Nominator(fnCanBeEvaluated).Nominate(expression)).Eval(expression); + } + + /// <summary> + /// Performs evaluation & replacement of independent sub-trees + /// </summary> + /// <param name="expression">The root of the expression tree.</param> + /// <returns>A new tree with sub-trees evaluated and replaced.</returns> + public static Expression Reduce(Expression expression) + { + return Reduce(expression, LocalVariableExpressionReducer.CanBeEvaluatedLocally); + } + + private static bool CanBeEvaluatedLocally(Expression expression) + { + if (expression.NodeType == ExpressionType.Constant) + { + return !(((ConstantExpression)expression).Value is IQueryable); + } + + return expression.NodeType != ExpressionType.Parameter; + } + + /// <summary> + /// Evaluates & replaces sub-trees when first candidate is reached (top-down) + /// </summary> + class SubtreeEvaluator : ExpressionVisitor + { + HashSet<Expression> candidates; + + internal SubtreeEvaluator(HashSet<Expression> candidates) + { + this.candidates = candidates; + } + + internal Expression Eval(Expression exp) + { + return this.Visit(exp); + } + + public override Expression Visit(Expression exp) + { + if (exp == null) + { + return null; + } + if (this.candidates.Contains(exp)) + { + return this.Evaluate(exp); + } + return base.Visit(exp); + } + + private Expression Evaluate(Expression e) + { + if (e.NodeType == ExpressionType.Constant) + { + return e; + } + LambdaExpression lambda = Expression.Lambda(e); + Delegate fn = lambda.Compile(); + return Expression.Constant(fn.DynamicInvoke(null), e.Type); + } + } + + /// <summary> + /// Performs bottom-up analysis to determine which nodes can possibly + /// be part of an evaluated sub-tree. + /// </summary> + class Nominator : ExpressionVisitor + { + Func<Expression, bool> fnCanBeEvaluated; + HashSet<Expression> candidates; + bool cannotBeEvaluated; + + internal Nominator(Func<Expression, bool> fnCanBeEvaluated) + { + this.fnCanBeEvaluated = fnCanBeEvaluated; + } + + internal HashSet<Expression> Nominate(Expression expression) + { + this.candidates = new HashSet<Expression>(); + this.Visit(expression); + return this.candidates; + } + + public override Expression Visit(Expression expression) + { + if (expression != null) + { + bool saveCannotBeEvaluated = this.cannotBeEvaluated; + this.cannotBeEvaluated = false; + base.Visit(expression); + if (!this.cannotBeEvaluated) + { + if (this.fnCanBeEvaluated(expression)) + { + this.candidates.Add(expression); + } + else + { + this.cannotBeEvaluated = true; + } + } + this.cannotBeEvaluated |= saveCannotBeEvaluated; + } + return expression; + } + } + } +} Modified: trunk/nhibernate/src/NHibernate.Linq/Visitors/LogicalExpressionReducer.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Linq/Visitors/LogicalExpressionReducer.cs 2008-08-15 05:37:47 UTC (rev 3704) +++ trunk/nhibernate/src/NHibernate.Linq/Visitors/LogicalExpressionReducer.cs 2008-08-15 11:25:15 UTC (rev 3705) @@ -12,9 +12,14 @@ /// </summary> //May be used for animal.Offspring.Any() == true - //Eventhough it is almost unnecessary to reduce not(not(true)) kind of expression, but simplified expressions are gold. + //Eventhough it is almost unnecessary to reduce not(not(true)) kind of expression(sql servers can easily optimize them, + //simplified expressions is gold for debugging. public class LogicalExpressionReducer:ExpressionVisitor { + public static Expression Reduce(Expression expr) + { + return new LogicalExpressionReducer().Visit(expr); + } protected override Expression VisitBinary(BinaryExpression expr) { bool modified; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |