FileContextCore/Query/Internal/EntityProjectionExpression.cs
// Copyright (c) morrisjdev. All rights reserved.
// Original copyright (c) .NET Foundation. All rights reserved.
// Modified version by morrisjdev
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Query;
namespace FileContextCore.Query.Internal
{
public class EntityProjectionExpression : Expression, IPrintableExpression
{
private readonly IDictionary<IProperty, Expression> _readExpressionMap;
private readonly IDictionary<INavigation, EntityShaperExpression> _navigationExpressionsCache
= new Dictionary<INavigation, EntityShaperExpression>();
public EntityProjectionExpression(
IEntityType entityType, IDictionary<IProperty, Expression> readExpressionMap)
{
EntityType = entityType;
_readExpressionMap = readExpressionMap;
}
public virtual IEntityType EntityType { get; }
public override Type Type => EntityType.ClrType;
public sealed override ExpressionType NodeType => ExpressionType.Extension;
public virtual EntityProjectionExpression UpdateEntityType(IEntityType derivedType)
{
var readExpressionMap = new Dictionary<IProperty, Expression>();
foreach (var kvp in _readExpressionMap)
{
var property = kvp.Key;
if (derivedType.IsAssignableFrom(property.DeclaringEntityType)
|| property.DeclaringEntityType.IsAssignableFrom(derivedType))
{
readExpressionMap[property] = kvp.Value;
}
}
return new EntityProjectionExpression(derivedType, readExpressionMap);
}
public virtual Expression BindProperty(IProperty property)
{
if (!EntityType.IsAssignableFrom(property.DeclaringEntityType)
&& !property.DeclaringEntityType.IsAssignableFrom(EntityType))
{
throw new InvalidOperationException(
$"Called EntityProjectionExpression.BindProperty() with incorrect IProperty. EntityType:{EntityType.DisplayName()}, Property:{property.Name}");
}
return _readExpressionMap[property];
}
public virtual void AddNavigationBinding(INavigation navigation, EntityShaperExpression entityShaper)
{
if (!EntityType.IsAssignableFrom(navigation.DeclaringEntityType)
&& !navigation.DeclaringEntityType.IsAssignableFrom(EntityType))
{
throw new InvalidOperationException(
$"Called EntityProjectionExpression.AddNavigationBinding() with incorrect INavigation. " +
$"EntityType:{EntityType.DisplayName()}, Property:{navigation.Name}");
}
_navigationExpressionsCache[navigation] = entityShaper;
}
public virtual EntityShaperExpression BindNavigation(INavigation navigation)
{
if (!EntityType.IsAssignableFrom(navigation.DeclaringEntityType)
&& !navigation.DeclaringEntityType.IsAssignableFrom(EntityType))
{
throw new InvalidOperationException(
$"Called EntityProjectionExpression.BindNavigation() with incorrect INavigation. " +
$"EntityType:{EntityType.DisplayName()}, Property:{navigation.Name}");
}
return _navigationExpressionsCache.TryGetValue(navigation, out var expression)
? expression
: null;
}
public virtual void Print(ExpressionPrinter expressionPrinter)
{
expressionPrinter.AppendLine(nameof(EntityProjectionExpression) + ":");
using (expressionPrinter.Indent())
{
foreach (var readExpressionMapEntry in _readExpressionMap)
{
expressionPrinter.Append(readExpressionMapEntry.Key + " -> ");
expressionPrinter.Visit(readExpressionMapEntry.Value);
expressionPrinter.AppendLine();
}
}
}
}
}