Skip to content

Commit

Permalink
Updated based on PR feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
mikary committed Mar 5, 2015
1 parent efc9682 commit 71dd657
Show file tree
Hide file tree
Showing 15 changed files with 157 additions and 326 deletions.
1 change: 1 addition & 0 deletions src/EntityFramework.Core/EntityFramework.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@
<Compile Include="Query\EntityLoadInfo.cs" />
<Compile Include="Query\ExpressionTreeVisitors\ExpressionStringBuilder.cs" />
<Compile Include="Query\ExpressionTreeVisitors\ExpressionTreeVisitorBase.cs" />
<Compile Include="Query\IEntityQueryable.cs" />
<Compile Include="Query\IIncludableQueryable.cs" />
<Compile Include="Infrastructure\DbContextActivator.cs" />
<Compile Include="DbContextOptions.cs" />
Expand Down
49 changes: 48 additions & 1 deletion src/EntityFramework.Core/Query/EntityQueryable`.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,22 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using JetBrains.Annotations;
using Microsoft.Data.Entity.Metadata;
using Microsoft.Data.Entity.Utilities;
using Remotion.Linq;

namespace Microsoft.Data.Entity.Query
{
public class EntityQueryable<TResult>
: QueryableBase<TResult>, IAsyncEnumerable<TResult>
: QueryableBase<TResult>, IAsyncEnumerable<TResult>, IEntityQueryable
{
private readonly LazyRef<Annotatable> _annotatable
= new LazyRef<Annotatable>(
() => new Annotatable());

public EntityQueryable([NotNull] EntityQueryProvider provider)
: base(Check.NotNull(provider, nameof(provider)))
{
Expand All @@ -28,5 +34,46 @@ IAsyncEnumerator<TResult> IAsyncEnumerable<TResult>.GetEnumerator()
{
return ((IAsyncQueryProvider)Provider).ExecuteAsync<TResult>(Expression).GetEnumerator();
}

public virtual Annotation AddAnnotation([NotNull] string annotationName, [NotNull] string value)
{
Check.NotNull(annotationName, nameof(annotationName));
Check.NotNull(value, nameof(value));

return _annotatable.Value.AddAnnotation(annotationName, value);
}

public virtual string this[[NotNull]string annotationName]
{
get
{
Check.NotNull(annotationName, annotationName);
return _annotatable.Value[annotationName];
}
}

public virtual IEnumerable<IAnnotation> Annotations
{
get
{
return _annotatable.Value.Annotations;
}
}

public virtual Annotation GetAnnotation([NotNull]string annotationName)
{
Check.NotNull(annotationName, nameof(annotationName));

return _annotatable.Value.GetAnnotation(annotationName);
}

public override string ToString()
{
return base.ToString() + string.Join(", ", _annotatable.Value.Annotations.Select(annotation => annotation.Value));
}

private class Annotatable : MetadataBase
{
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ protected EntityQueryableExpressionTreeVisitor([NotNull] EntityQueryModelVisitor

protected override Expression VisitConstantExpression(ConstantExpression constantExpression)
{
if (constantExpression.Type.GetTypeInfo().IsGenericType
&& constantExpression.Type.GetGenericTypeDefinition() == typeof(EntityQueryable<>))
var entityQueryable = constantExpression.Value as IEntityQueryable;

if (entityQueryable != null)
{
return VisitEntityQueryable(((IQueryable)constantExpression.Value).ElementType);
return VisitEntityQueryable(entityQueryable.ElementType);
}

return constantExpression;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Linq;
using Microsoft.Data.Entity.Metadata;

namespace Microsoft.Data.Entity.Relational.Query
namespace Microsoft.Data.Entity.Query
{
public interface IRelationalCustomQueryable : IQueryable
public interface IEntityQueryable : IMetadata, IQueryable
{
string Query { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@
<Compile Include="Query\CommandParameter.cs" />
<Compile Include="Query\EqualityPredicateOptimizer.cs" />
<Compile Include="Query\Expressions\ColumnAggregateExpression.cs" />
<Compile Include="Query\Expressions\CustomTableExpression.cs" />
<Compile Include="Query\Expressions\RawSqlDerivedTableExpression.cs" />
<Compile Include="Query\Expressions\DiscriminatorPredicateExpression.cs" />
<Compile Include="Query\Expressions\InExpressionBase.cs" />
<Compile Include="Query\Expressions\NotInExpression.cs" />
Expand All @@ -167,7 +167,6 @@
<Compile Include="Query\IncludeCollectionIterator.cs" />
<Compile Include="Query\ExpressionTreeVisitors\QueryFlatteningExpressionTreeVisitor.cs" />
<Compile Include="Query\IRelationalQueryContextFactory.cs" />
<Compile Include="Query\IRelationalCustomQueryable.cs" />
<Compile Include="Query\Methods\ContainsTranslator.cs" />
<Compile Include="Query\OffsetValueReaderDecorator.cs" />
<Compile Include="Query\QueryingEnumerable.cs" />
Expand All @@ -193,8 +192,6 @@
<Compile Include="Query\ExpressionTreeVisitors\RelationalOrderingExpressionTreeVisitor.cs" />
<Compile Include="Query\ExpressionTreeVisitors\RelationalProjectionExpressionTreeVisitor.cs" />
<Compile Include="Query\ExpressionTreeVisitors\RelationalEntityQueryableExpressionTreeVisitor.cs" />
<Compile Include="Query\RelationalCustomQueryable`.cs" />
<Compile Include="Query\RelationalCustomQueryProvider.cs" />
<Compile Include="Query\RelationalQueryContextFactory.cs" />
<Compile Include="Query\Sql\ISqlExpressionVisitor.cs" />
<Compile Include="Query\Expressions\ColumnExpression.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Linq;
using System.Linq.Expressions;
using JetBrains.Annotations;
using Microsoft.Data.Entity.Metadata;
using Microsoft.Data.Entity.Query;
using Microsoft.Data.Entity.Query.ExpressionTreeVisitors;
using Microsoft.Data.Entity.Relational.Query.Expressions;
Expand Down Expand Up @@ -70,15 +71,47 @@ protected override Expression VisitMethodCallExpression([NotNull] MethodCallExpr

protected override Expression VisitConstantExpression(ConstantExpression constantExpression)
{
var queryable = constantExpression.Value as IRelationalCustomQueryable;
var entityQueryable = constantExpression.Value as IEntityQueryable;

return (queryable != null)
? VisitRelationalCustomQueryable(queryable.Query, queryable.ElementType)
: base.VisitConstantExpression(constantExpression);
}
if (entityQueryable != null)
{
if (entityQueryable["sql"] != null)
{
return VisitRawSqlQueryable(entityQueryable.ElementType, entityQueryable["sql"]);
}
}

return base.VisitConstantExpression(constantExpression);
}

protected override Expression VisitEntityQueryable(Type elementType)
{
return VisitSelectExpression(elementType,
(entityType, tableName) =>
new TableExpression(
tableName,
QueryModelVisitor.QueryCompilationContext.GetSchema(entityType),
_querySource.ItemName.StartsWith("<generated>_")
? tableName.First().ToString().ToLower()
: _querySource.ItemName,
_querySource));
}

protected virtual Expression VisitRawSqlQueryable(Type elementType, string rawSql)
{
return VisitSelectExpression(elementType,
(entityType, tableName) =>
new RawSqlDerivedTableExpression(
rawSql,
_querySource.ItemName.StartsWith("<generated>_")
? tableName.First().ToString().ToLower()
: _querySource.ItemName,
_querySource));
}

private Expression VisitSelectExpression(
Type elementType,
Func<IEntityType, string, TableExpressionBase> createTableExpression)
{
Check.NotNull(elementType, nameof(elementType));

Expand All @@ -88,15 +121,7 @@ protected override Expression VisitEntityQueryable(Type elementType)
var selectExpression = new SelectExpression();
var tableName = QueryModelVisitor.QueryCompilationContext.GetTableName(entityType);

selectExpression
.AddTable(
new TableExpression(
tableName,
QueryModelVisitor.QueryCompilationContext.GetSchema(entityType),
_querySource.ItemName.StartsWith("<generated>_")
? tableName.First().ToString().ToLower()
: _querySource.ItemName,
_querySource));
selectExpression.AddTable(createTableExpression(entityType, tableName));

QueryModelVisitor.AddQuery(_querySource, selectExpression);

Expand Down Expand Up @@ -158,82 +183,5 @@ var keyFactory
Expression.Call(queryMethodInfo, queryMethodArguments),
_readerParameter));
}

protected Expression VisitRelationalCustomQueryable(string sql, Type elementType)
{
Check.NotNull(elementType, nameof(elementType));

var queryMethodInfo = RelationalQueryModelVisitor.CreateValueReaderMethodInfo;
var entityType = QueryModelVisitor.QueryCompilationContext.Model.GetEntityType(elementType);

var selectExpression = new SelectExpression();
var tableName = QueryModelVisitor.QueryCompilationContext.GetTableName(entityType);

selectExpression
.AddTable(
new CustomTableExpression(
sql,
QueryModelVisitor.QueryCompilationContext.GetSchema(entityType),
_querySource.ItemName.StartsWith("<generated>_")
? tableName.First().ToString().ToLower()
: _querySource.ItemName,
_querySource));

QueryModelVisitor.AddQuery(_querySource, selectExpression);

var queryMethodArguments
= new List<Expression>
{
Expression.Constant(_querySource),
EntityQueryModelVisitor.QueryContextParameter,
EntityQueryModelVisitor.QuerySourceScopeParameter,
_readerParameter
};

if (QueryModelVisitor.QuerySourceRequiresMaterialization(_querySource))
{
foreach (var property in entityType.Properties)
{
selectExpression.AddToProjection(
QueryModelVisitor.QueryCompilationContext
.GetColumnName(property),
property,
_querySource);
}

queryMethodInfo = RelationalQueryModelVisitor.CreateEntityMethodInfo.MakeGenericMethod(elementType);

var keyProperties
= entityType.GetPrimaryKey().Properties;

var keyFactory
= QueryModelVisitor.QueryCompilationContext.EntityKeyFactorySource
.GetKeyFactory(keyProperties);

var materializer
= QueryModelVisitor.QueryCompilationContext.EntityMaterializerSource
.GetMaterializer(entityType);

queryMethodArguments.AddRange(
new Expression[]
{
Expression.Constant(0),
Expression.Constant(entityType),
Expression.Constant(QueryModelVisitor.QuerySourceRequiresTracking(_querySource)),
Expression.Constant(keyFactory),
Expression.Constant(keyProperties),
Expression.Constant(materializer)
});
}

return Expression.Call(
QueryModelVisitor.QueryCompilationContext.QueryMethodProvider.QueryMethod
.MakeGenericMethod(queryMethodInfo.ReturnType),
EntityQueryModelVisitor.QueryContextParameter,
Expression.Constant(new CommandBuilder(selectExpression, QueryModelVisitor.QueryCompilationContext)),
Expression.Lambda(
Expression.Call(queryMethodInfo, queryMethodArguments),
_readerParameter));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,22 @@

namespace Microsoft.Data.Entity.Relational.Query.Expressions
{
public class CustomTableExpression : TableExpressionBase
public class RawSqlDerivedTableExpression : TableExpressionBase
{
public CustomTableExpression(
[NotNull] string table,
[CanBeNull] string schema,
public RawSqlDerivedTableExpression(
[NotNull] string rawSql,
[NotNull] string alias,
[NotNull] IQuerySource querySource)
: base(
Check.NotNull(querySource, nameof(querySource)),
Check.NotEmpty(alias, nameof(alias)))
{
Check.NotEmpty(table, nameof(table));
Check.NotEmpty(rawSql, nameof(rawSql));

Table = table;
Schema = schema;
RawSql = rawSql;
}

public virtual string Table { get; }

public virtual string Schema { get; }
public virtual string RawSql { get; }

public override Expression Accept([NotNull] ExpressionTreeVisitor visitor)
{
Expand All @@ -38,13 +34,13 @@ public override Expression Accept([NotNull] ExpressionTreeVisitor visitor)
var specificVisitor = visitor as ISqlExpressionVisitor;

return specificVisitor != null
? specificVisitor.VisitCustomTableExpression(this)
? specificVisitor.VisitRawSqlDerivedTableExpression(this)
: base.Accept(visitor);
}

public override string ToString()
{
return Table + " " + Alias;
return RawSql + " " + Alias;
}
}
}
Loading

0 comments on commit 71dd657

Please sign in to comment.