diff --git a/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs b/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs
index 3cf6470d407..f7d5e601fff 100644
--- a/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs
+++ b/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs
@@ -921,6 +921,12 @@ public static string MappedFunctionNotFound([CanBeNull] object entityType, [CanB
GetString("MappedFunctionNotFound", nameof(entityType), nameof(functionName)),
entityType, functionName);
+ ///
+ /// Unable to identify the concrete entity type to materialize in TPT hierarchy.
+ ///
+ public static string QueryUnableToIdentifyConcreteTypeInTPT
+ => GetString("QueryUnableToIdentifyConcreteTypeInTPT");
+
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);
diff --git a/src/EFCore.Relational/Properties/RelationalStrings.resx b/src/EFCore.Relational/Properties/RelationalStrings.resx
index 59b0551fc94..87d70631191 100644
--- a/src/EFCore.Relational/Properties/RelationalStrings.resx
+++ b/src/EFCore.Relational/Properties/RelationalStrings.resx
@@ -679,4 +679,7 @@
The entity type '{entityType}' is mapped to the DbFunction named '{functionName}', but no DbFunction with that name was found in the model. Ensure that the entity type mapping is configured using the model name of a function in the model.
+
+ Unable to identify the concrete entity type to materialize in TPT hierarchy.
+
\ No newline at end of file
diff --git a/src/EFCore.Relational/Query/EntityProjectionExpression.cs b/src/EFCore.Relational/Query/EntityProjectionExpression.cs
index cf957cd0a0d..242cda9f751 100644
--- a/src/EFCore.Relational/Query/EntityProjectionExpression.cs
+++ b/src/EFCore.Relational/Query/EntityProjectionExpression.cs
@@ -23,49 +23,49 @@ namespace Microsoft.EntityFrameworkCore.Query
///
public class EntityProjectionExpression : Expression
{
- private readonly IDictionary _propertyExpressionsCache
- = new Dictionary();
-
- private readonly IDictionary _navigationExpressionsCache
+ private readonly IDictionary _propertyExpressionMap = new Dictionary();
+ private readonly IDictionary _ownedNavigationMap
= new Dictionary();
- private readonly TableExpressionBase _innerTable;
- private readonly bool _nullable;
-
///
/// Creates a new instance of the class.
///
/// The entity type to shape.
/// The table from which entity columns are being projected out.
/// A bool value indicating whether this entity instance can be null.
+ [Obsolete("Use the constructor which takes populated column expressions map.", error: true)]
public EntityProjectionExpression([NotNull] IEntityType entityType, [NotNull] TableExpressionBase innerTable, bool nullable)
{
- Check.NotNull(entityType, nameof(entityType));
- Check.NotNull(innerTable, nameof(innerTable));
-
- EntityType = entityType;
- _innerTable = innerTable;
- _nullable = nullable;
+ throw new NotSupportedException();
}
///
/// Creates a new instance of the class.
///
/// The entity type to shape.
- /// A dictionary of column expressions corresponding to properties of the entity type.
- public EntityProjectionExpression([NotNull] IEntityType entityType, [NotNull] IDictionary propertyExpressions)
+ /// A dictionary of column expressions corresponding to properties of the entity type.
+ /// A dictionary of to identify each entity type in hierarchy.
+ public EntityProjectionExpression(
+ [NotNull] IEntityType entityType,
+ [NotNull] IDictionary propertyExpressionMap,
+ [CanBeNull] IReadOnlyDictionary entityTypeIdentifyingExpressionMap = null)
{
Check.NotNull(entityType, nameof(entityType));
- Check.NotNull(propertyExpressions, nameof(propertyExpressions));
+ Check.NotNull(propertyExpressionMap, nameof(propertyExpressionMap));
EntityType = entityType;
- _propertyExpressionsCache = propertyExpressions;
+ _propertyExpressionMap = propertyExpressionMap;
+ EntityTypeIdentifyingExpressionMap = entityTypeIdentifyingExpressionMap;
}
///
/// The entity type being projected out.
///
public virtual IEntityType EntityType { get; }
+ ///
+ /// Dictionary of entity type identifying expressions.
+ ///
+ public virtual IReadOnlyDictionary EntityTypeIdentifyingExpressionMap { get; }
///
public sealed override ExpressionType NodeType => ExpressionType.Extension;
///
@@ -76,27 +76,31 @@ protected override Expression VisitChildren(ExpressionVisitor visitor)
{
Check.NotNull(visitor, nameof(visitor));
- if (_innerTable != null)
+ var changed = false;
+ var propertyExpressionMap = new Dictionary();
+ foreach (var expression in _propertyExpressionMap)
{
- var table = (TableExpressionBase)visitor.Visit(_innerTable);
+ var newExpression = (ColumnExpression)visitor.Visit(expression.Value);
+ changed |= newExpression != expression.Value;
- return table != _innerTable
- ? new EntityProjectionExpression(EntityType, table, _nullable)
- : this;
+ propertyExpressionMap[expression.Key] = newExpression;
}
- var changed = false;
- var newCache = new Dictionary();
- foreach (var expression in _propertyExpressionsCache)
+ Dictionary entityTypeIdentifyingExpressionMap = null;
+ if (EntityTypeIdentifyingExpressionMap != null)
{
- var newExpression = (ColumnExpression)visitor.Visit(expression.Value);
- changed |= newExpression != expression.Value;
+ entityTypeIdentifyingExpressionMap = new Dictionary();
+ foreach (var expression in EntityTypeIdentifyingExpressionMap)
+ {
+ var newExpression = (SqlExpression)visitor.Visit(expression.Value);
+ changed |= newExpression != expression.Value;
- newCache[expression.Key] = newExpression;
+ entityTypeIdentifyingExpressionMap[expression.Key] = newExpression;
+ }
}
return changed
- ? new EntityProjectionExpression(EntityType, newCache)
+ ? new EntityProjectionExpression(EntityType, propertyExpressionMap, entityTypeIdentifyingExpressionMap)
: this;
}
@@ -106,18 +110,14 @@ protected override Expression VisitChildren(ExpressionVisitor visitor)
/// A new entity projection expression which can project nullable entity.
public virtual EntityProjectionExpression MakeNullable()
{
- if (_innerTable != null)
+ var propertyExpressionMap = new Dictionary();
+ foreach (var expression in _propertyExpressionMap)
{
- return new EntityProjectionExpression(EntityType, _innerTable, nullable: true);
+ propertyExpressionMap[expression.Key] = expression.Value.MakeNullable();
}
- var newCache = new Dictionary();
- foreach (var expression in _propertyExpressionsCache)
- {
- newCache[expression.Key] = expression.Value.MakeNullable();
- }
-
- return new EntityProjectionExpression(EntityType, newCache);
+ // We don't need to process EntityTypeIdentifyingExpressionMap because they are already nullable
+ return new EntityProjectionExpression(EntityType, propertyExpressionMap, EntityTypeIdentifyingExpressionMap);
}
///
@@ -129,23 +129,32 @@ public virtual EntityProjectionExpression UpdateEntityType([NotNull] IEntityType
{
Check.NotNull(derivedType, nameof(derivedType));
- if (_innerTable != null)
- {
- return new EntityProjectionExpression(derivedType, _innerTable, _nullable);
- }
-
- var propertyExpressionCache = new Dictionary();
- foreach (var kvp in _propertyExpressionsCache)
+ var propertyExpressionMap = new Dictionary();
+ foreach (var kvp in _propertyExpressionMap)
{
var property = kvp.Key;
if (derivedType.IsAssignableFrom(property.DeclaringEntityType)
|| property.DeclaringEntityType.IsAssignableFrom(derivedType))
{
- propertyExpressionCache[property] = kvp.Value;
+ propertyExpressionMap[property] = kvp.Value;
+ }
+ }
+
+ Dictionary entityTypeIdentifyingExpressionMap = null;
+ if (EntityTypeIdentifyingExpressionMap != null)
+ {
+ entityTypeIdentifyingExpressionMap = new Dictionary();
+ foreach (var kvp in EntityTypeIdentifyingExpressionMap)
+ {
+ var entityType = kvp.Key;
+ if (entityType.IsStrictlyDerivedFrom(derivedType))
+ {
+ entityTypeIdentifyingExpressionMap[entityType] = kvp.Value;
+ }
}
}
- return new EntityProjectionExpression(derivedType, propertyExpressionCache);
+ return new EntityProjectionExpression(derivedType, propertyExpressionMap, entityTypeIdentifyingExpressionMap);
}
///
@@ -168,13 +177,7 @@ public virtual ColumnExpression BindProperty([NotNull] IProperty property)
property.Name));
}
- if (!_propertyExpressionsCache.TryGetValue(property, out var expression))
- {
- expression = new ColumnExpression(property, _innerTable, _nullable);
- _propertyExpressionsCache[property] = expression;
- }
-
- return expression;
+ return _propertyExpressionMap[property];
}
///
@@ -198,7 +201,7 @@ public virtual void AddNavigationBinding([NotNull] INavigation navigation, [NotN
navigation.Name));
}
- _navigationExpressionsCache[navigation] = entityShaper;
+ _ownedNavigationMap[navigation] = entityShaper;
}
///
@@ -222,7 +225,7 @@ public virtual EntityShaperExpression BindNavigation([NotNull] INavigation navig
navigation.Name));
}
- return _navigationExpressionsCache.TryGetValue(navigation, out var expression)
+ return _ownedNavigationMap.TryGetValue(navigation, out var expression)
? expression
: null;
}
diff --git a/src/EFCore.Relational/Query/RelationalEntityShaperExpression.cs b/src/EFCore.Relational/Query/RelationalEntityShaperExpression.cs
index 974a67e2b13..5f47d60c19e 100644
--- a/src/EFCore.Relational/Query/RelationalEntityShaperExpression.cs
+++ b/src/EFCore.Relational/Query/RelationalEntityShaperExpression.cs
@@ -4,10 +4,13 @@
using System;
using System.Linq;
using System.Linq.Expressions;
+using System.Reflection;
using JetBrains.Annotations;
+using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
+using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Utilities;
namespace Microsoft.EntityFrameworkCore.Query
@@ -23,6 +26,14 @@ namespace Microsoft.EntityFrameworkCore.Query
///
public class RelationalEntityShaperExpression : EntityShaperExpression
{
+ private static readonly MethodInfo _createUnableToIdentifyConcreteTypeException
+ = typeof(RelationalEntityShaperExpression).GetTypeInfo()
+ .GetDeclaredMethod(nameof(CreateUnableToIdentifyConcreteTypeException));
+
+ [UsedImplicitly]
+ private static Exception CreateUnableToIdentifyConcreteTypeException()
+ => new InvalidOperationException(RelationalStrings.QueryUnableToIdentifyConcreteTypeInTPT);
+
///
/// Creates a new instance of the class.
///
@@ -55,11 +66,35 @@ protected override LambdaExpression GenerateMaterializationCondition(IEntityType
{
Check.NotNull(entityType, nameof(EntityType));
- var baseCondition = base.GenerateMaterializationCondition(entityType, nullable);
+ LambdaExpression baseCondition;
+ if (entityType.GetDiscriminatorProperty() == null
+ && entityType.GetDirectlyDerivedTypes().Any())
+ {
+ // TPT
+ var valueBufferParameter = Parameter(typeof(ValueBuffer));
+ var body = entityType.IsAbstract()
+ ? Block(Throw(Call(_createUnableToIdentifyConcreteTypeException)), Constant(null, typeof(IEntityType)))
+ : (Expression)Constant(entityType, typeof(IEntityType));
+
+ var concreteEntityTypes = entityType.GetDerivedTypes().Where(dt => !dt.IsAbstract()).ToArray();
+ for (var i = 0; i < concreteEntityTypes.Length; i++)
+ {
+ body = Condition(
+ valueBufferParameter.CreateValueBufferReadValueExpression(typeof(bool), i, property: null),
+ Constant(concreteEntityTypes[i], typeof(IEntityType)),
+ body);
+ }
+
+ baseCondition = Lambda(body, valueBufferParameter);
+ }
+ else
+ {
+ baseCondition = base.GenerateMaterializationCondition(entityType, nullable);
+ }
if (entityType.FindPrimaryKey() != null)
{
- var linkingFks = entityType.GetViewOrTableMappings().SingleOrDefault()?.Table.GetRowInternalForeignKeys(entityType);
+ var linkingFks = entityType.GetViewOrTableMappings().FirstOrDefault()?.Table.GetRowInternalForeignKeys(entityType);
if (linkingFks != null
&& linkingFks.Any())
{
diff --git a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs
index 24215d82b11..d95f79832ad 100644
--- a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs
+++ b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs
@@ -755,16 +755,47 @@ protected override ShapedQueryExpression TranslateOfType(ShapedQueryExpression s
var derivedType = entityType.GetDerivedTypes().SingleOrDefault(et => et.ClrType == resultType);
if (derivedType != null)
{
- if (!derivedType.GetRootType().GetIsDiscriminatorMappingComplete()
- || !derivedType.GetAllBaseTypesInclusiveAscending()
- .All(e => (e == derivedType || e.IsAbstract()) && !HasSiblings(e)))
+ var discriminatorProperty = entityType.GetDiscriminatorProperty();
+ if (discriminatorProperty == null)
{
var selectExpression = (SelectExpression)source.QueryExpression;
var concreteEntityTypes = derivedType.GetConcreteDerivedTypesInclusive().ToList();
var projectionBindingExpression = (ProjectionBindingExpression)entityShaperExpression.ValueBufferExpression;
- var entityProjectionExpression = (EntityProjectionExpression)selectExpression.GetMappedProjection(
- projectionBindingExpression.ProjectionMember);
- var discriminatorColumn = entityProjectionExpression.BindProperty(entityType.GetDiscriminatorProperty());
+
+ var projectionMember = projectionBindingExpression.ProjectionMember;
+ Check.DebugAssert(
+ new ProjectionMember().Equals(projectionMember),
+ "Invalid ProjectionMember when processing OfType");
+
+ var entityProjectionExpression = (EntityProjectionExpression)selectExpression.GetMappedProjection(projectionMember);
+
+ var predicate = entityProjectionExpression.EntityTypeIdentifyingExpressionMap
+ .Where(kvp => concreteEntityTypes.Contains(kvp.Key))
+ .Select(kvp => kvp.Value)
+ .Aggregate((l, r) => _sqlExpressionFactory.OrElse(l, r));
+
+ selectExpression.ApplyPredicate(predicate);
+ selectExpression.ReplaceProjectionMapping(
+ new Dictionary
+ {
+ { projectionMember, entityProjectionExpression.UpdateEntityType(derivedType) }
+ });
+ }
+ else if (!derivedType.GetRootType().GetIsDiscriminatorMappingComplete()
+ || !derivedType.GetAllBaseTypesInclusiveAscending()
+ .All(e => (e == derivedType || e.IsAbstract()) && !HasSiblings(e)))
+ {
+ var selectExpression = (SelectExpression)source.QueryExpression;
+ var concreteEntityTypes = derivedType.GetConcreteDerivedTypesInclusive().ToList();
+ var projectionBindingExpression = (ProjectionBindingExpression)entityShaperExpression.ValueBufferExpression;
+
+ var projectionMember = projectionBindingExpression.ProjectionMember;
+ Check.DebugAssert(
+ new ProjectionMember().Equals(projectionMember),
+ "Invalid ProjectionMember when processing OfType");
+
+ var entityProjectionExpression = (EntityProjectionExpression)selectExpression.GetMappedProjection(projectionMember);
+ var discriminatorColumn = entityProjectionExpression.BindProperty(discriminatorProperty);
var predicate = concreteEntityTypes.Count == 1
? _sqlExpressionFactory.Equal(
@@ -776,19 +807,10 @@ protected override ShapedQueryExpression TranslateOfType(ShapedQueryExpression s
negated: false);
selectExpression.ApplyPredicate(predicate);
-
- var projectionMember = projectionBindingExpression.ProjectionMember;
-
- Check.DebugAssert(
- new ProjectionMember().Equals(projectionMember),
- "Invalid ProjectionMember when processing OfType");
-
- var entityProjection = (EntityProjectionExpression)selectExpression.GetMappedProjection(projectionMember);
-
selectExpression.ReplaceProjectionMapping(
new Dictionary
{
- { projectionMember, entityProjection.UpdateEntityType(derivedType) }
+ { projectionMember, entityProjectionExpression.UpdateEntityType(derivedType) }
});
}
@@ -1296,16 +1318,34 @@ private Expression TryExpand(Expression source, MemberIdentity member)
var innerShaper = entityProjectionExpression.BindNavigation(navigation);
if (innerShaper == null)
{
- if (entityType.GetViewOrTableMappings().Single().Table
- .GetReferencingRowInternalForeignKeys(foreignKey.PrincipalEntityType)?.Contains(foreignKey) == true)
+ // Owned types don't support inheritance See https://github.com/dotnet/efcore/issues/9630
+ // So there is no handling for dependent having TPT
+
+ // If navigation is defined on derived type and entity type is part of TPT then we need to get ITableBase for derived type.
+ var table = navigation.DeclaringEntityType.BaseType == null
+ || entityType.GetDiscriminatorProperty() != null
+ ? navigation.DeclaringEntityType.GetViewOrTableMappings().Single().Table
+ : navigation.DeclaringEntityType.GetViewOrTableMappings().Select(tm => tm.Table)
+ .Except(navigation.DeclaringEntityType.BaseType.GetViewOrTableMappings().Select(tm => tm.Table))
+ .Single();
+ if (table.GetReferencingRowInternalForeignKeys(foreignKey.PrincipalEntityType)?.Contains(foreignKey) == true)
{
- // Since we are not going to update table or visit, we always generate propertyExpressions
- // We just first column of PK to figure out the base table
+ // Mapped to same table
+ // We get identifying column to figure out tableExpression to pull columns from and nullability of most principal side
var identifyingColumn = entityProjectionExpression.BindProperty(entityType.FindPrimaryKey().Properties.First());
+ var principalNullable = identifyingColumn.IsNullable
+ // Also make nullable if navigation is on derived type and and principal is TPT
+ // Since identifying PK would be non-nullable but principal can still be null
+ // Derived owned navigation does not de-dupe the PK column which for principal is from base table
+ // and for dependent on derived table
+ || (entityType.GetDiscriminatorProperty() == null
+ && navigation.DeclaringEntityType.IsStrictlyDerivedFrom(entityShaperExpression.EntityType));
+
var propertyExpressions = identifyingColumn.Table is TableExpression innerTable
- ? GetPropertyExpressionsFromTable(targetEntityType, innerTable, identifyingColumn.IsNullable)
- // Pull columns out of inner subquery
- : GetPropertyExpressionsFromSubquery(targetEntityType, identifyingColumn, identifyingColumn.IsNullable);
+ ? GetPropertyExpressionsFromTable(
+ targetEntityType, table, _selectExpression, innerTable, principalNullable)
+ // If the principal table is SelectExpression then we may need to populate inner projection
+ : GetPropertyExpressionsFromSubquery(targetEntityType, table, identifyingColumn, principalNullable);
innerShaper = new RelationalEntityShaperExpression(
targetEntityType, new EntityProjectionExpression(targetEntityType, propertyExpressions), true);
@@ -1334,10 +1374,10 @@ private Expression TryExpand(Expression source, MemberIdentity member)
var joinPredicate = _sqlTranslator.Translate(Expression.Equal(outerKey, innerKey));
_selectExpression.AddLeftJoin(innerSelectExpression, joinPredicate);
var leftJoinTable = ((LeftJoinExpression)_selectExpression.Tables.Last()).Table;
+ var propertyExpressions = GetPropertyExpressionsFromJoinedTable(targetEntityType, table, leftJoinTable);
+
innerShaper = new RelationalEntityShaperExpression(
- targetEntityType,
- new EntityProjectionExpression(targetEntityType, leftJoinTable, true),
- true);
+ targetEntityType, new EntityProjectionExpression(targetEntityType, propertyExpressions), true);
}
entityProjectionExpression.AddNavigationBinding(navigation, innerShaper);
@@ -1346,13 +1386,19 @@ private Expression TryExpand(Expression source, MemberIdentity member)
return innerShaper;
}
+ private static IDictionary GetPropertyExpressionsFromSubquery(
+ IEntityType entityType, ITableBase table, ColumnExpression identifyingColumn, bool nullable)
+ {
+ var subquery = (SelectExpression)identifyingColumn.Table;
+ var subqueryIdentifyingColumn = (ColumnExpression)subquery.Projection
+ .SingleOrDefault(e => string.Equals(e.Alias, identifyingColumn.Name, StringComparison.OrdinalIgnoreCase)).Expression;
+ var subqueryPropertyExpressions = subqueryIdentifyingColumn.Table is TableExpression innerTable
+ ? GetPropertyExpressionsFromTable(entityType, table, subquery, innerTable, nullable)
+ : GetPropertyExpressionsFromSubquery(entityType, table, subqueryIdentifyingColumn, nullable);
- private static IDictionary LiftPropertyExpressionsFromSubquery(
- IDictionary propertyExpressions, SelectExpression subquery)
- {
var newPropertyExpressions = new Dictionary();
- foreach (var item in propertyExpressions)
+ foreach (var item in subqueryPropertyExpressions)
{
newPropertyExpressions[item.Key] = new ColumnExpression(
subquery.Projection[subquery.AddToProjection(item.Value)], subquery);
@@ -1361,28 +1407,49 @@ private static IDictionary LiftPropertyExpressionsF
return newPropertyExpressions;
}
- private static IDictionary GetPropertyExpressionsFromSubquery(
- IEntityType entityType, ColumnExpression identifyingColumn, bool nullable)
+ private static IDictionary GetPropertyExpressionsFromTable(
+ IEntityType entityType, ITableBase table, SelectExpression selectExpression, TableExpression tableExpression, bool nullable)
{
- var subquery = (SelectExpression)identifyingColumn.Table;
- var subqueryIdentifyingColumn = (ColumnExpression)subquery.Projection
- .SingleOrDefault(e => string.Equals(e.Alias, identifyingColumn.Name, StringComparison.OrdinalIgnoreCase)).Expression;
+ if (!string.Equals(tableExpression.Name, table.Name, StringComparison.OrdinalIgnoreCase))
+ {
+ // Fetch the table for the type which is defininig the navigation since dependent would be in that table
+ tableExpression = selectExpression.Tables
+ .Select(t => (t as InnerJoinExpression)?.Table ?? (t as LeftJoinExpression)?.Table ?? t)
+ .Cast()
+ .First(t => string.Equals(t.Name, table.Name, StringComparison.OrdinalIgnoreCase));
+ }
- var subqueryPropertyExpressions = subqueryIdentifyingColumn.Table is TableExpression innerTable
- ? GetPropertyExpressionsFromTable(entityType, innerTable, nullable)
- : GetPropertyExpressionsFromSubquery(entityType, subqueryIdentifyingColumn, nullable);
+ var propertyExpressions = new Dictionary();
+ foreach (var property in entityType
+ .GetAllBaseTypes().Concat(entityType.GetDerivedTypesInclusive()).SelectMany(EntityTypeExtensions.GetDeclaredProperties))
+ {
+ var column = table is ITable
+ ? (IColumnBase)property.GetTableColumnMappings().Where(cm => cm.TableMapping.Table == table
+ && cm.TableMapping.EntityType == property.DeclaringEntityType).Single().Column
+ : property.GetViewColumnMappings().Where(cm => cm.TableMapping.Table == table
+ && cm.TableMapping.EntityType == property.DeclaringEntityType).Single().Column;
+
+ propertyExpressions[property] = new ColumnExpression(
+ property, column, tableExpression, nullable || !property.IsPrimaryKey());
+ }
- return LiftPropertyExpressionsFromSubquery(subqueryPropertyExpressions, subquery);
+ return propertyExpressions;
}
- private static IDictionary GetPropertyExpressionsFromTable(
- IEntityType entityType, TableExpression table, bool nullable)
+ private static IDictionary GetPropertyExpressionsFromJoinedTable(
+ IEntityType entityType, ITableBase table, TableExpressionBase tableExpression)
{
var propertyExpressions = new Dictionary();
foreach (var property in entityType
.GetAllBaseTypes().Concat(entityType.GetDerivedTypesInclusive()).SelectMany(EntityTypeExtensions.GetDeclaredProperties))
{
- propertyExpressions[property] = new ColumnExpression(property, table, nullable || !property.IsPrimaryKey());
+ var column = table is ITable
+ ? (IColumnBase)property.GetTableColumnMappings().Where(cm => cm.TableMapping.Table == table
+ && cm.TableMapping.EntityType == property.DeclaringEntityType).Single().Column
+ : property.GetViewColumnMappings().Where(cm => cm.TableMapping.Table == table
+ && cm.TableMapping.EntityType == property.DeclaringEntityType).Single().Column;
+
+ propertyExpressions[property] = new ColumnExpression(property, column, tableExpression, nullable: true);
}
return propertyExpressions;
diff --git a/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.cs
index 00921b816cd..40e97ee6a14 100644
--- a/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.cs
+++ b/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.cs
@@ -106,6 +106,8 @@ private static readonly MethodInfo _collectionAccessorAddMethodInfo
// States to convert code to data reader read
private readonly IDictionary> _materializationContextBindings
= new Dictionary>();
+ private readonly IDictionary entityTypeIdentifyingExpressionOffsets
+ = new Dictionary();
public ShaperProcessingExpressionVisitor(
RelationalShapedQueryCompilingExpressionVisitor parentVisitor,
@@ -343,8 +345,9 @@ protected override Expression VisitBinary(BinaryExpression binaryExpression)
var newExpression = (NewExpression)binaryExpression.Right;
var projectionBindingExpression = (ProjectionBindingExpression)newExpression.Arguments[0];
- _materializationContextBindings[parameterExpression]
- = (IDictionary)GetProjectionIndex(projectionBindingExpression);
+ var propertyMap = (IDictionary)GetProjectionIndex(projectionBindingExpression);
+ _materializationContextBindings[parameterExpression] = propertyMap;
+ entityTypeIdentifyingExpressionOffsets[parameterExpression] = propertyMap.Values.Max() + 1;
var updatedExpression = Expression.New(
newExpression.Constructor,
@@ -371,14 +374,15 @@ protected override Expression VisitExtension(Expression extensionExpression)
switch (extensionExpression)
{
- case EntityShaperExpression entityShaperExpression:
+ case RelationalEntityShaperExpression entityShaperExpression:
{
var key = GenerateKey((ProjectionBindingExpression)entityShaperExpression.ValueBufferExpression);
if (!_variableShaperMapping.TryGetValue(key, out var accessor))
{
var entityParameter = Expression.Parameter(entityShaperExpression.Type);
_variables.Add(entityParameter);
- var entityMaterializationExpression = Visit(_parentVisitor.InjectEntityMaterializers(entityShaperExpression));
+ var entityMaterializationExpression = _parentVisitor.InjectEntityMaterializers(entityShaperExpression);
+ entityMaterializationExpression = Visit(entityMaterializationExpression);
_expressions.Add(Expression.Assign(entityParameter, entityMaterializationExpression));
@@ -818,19 +822,17 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp
&& methodCallExpression.Method.GetGenericMethodDefinition() == Infrastructure.ExpressionExtensions.ValueBufferTryReadValueMethod)
{
var property = (IProperty)((ConstantExpression)methodCallExpression.Arguments[2]).Value;
- var propertyProjectionMap = methodCallExpression.Arguments[0] is ProjectionBindingExpression projectionBindingExpression
- ? (IDictionary)GetProjectionIndex(projectionBindingExpression)
- : _materializationContextBindings[
- (ParameterExpression)((MethodCallExpression)methodCallExpression.Arguments[0]).Object];
-
- var projectionIndex = propertyProjectionMap[property];
+ var mappingParameter = (ParameterExpression)((MethodCallExpression)methodCallExpression.Arguments[0]).Object;
+ var projectionIndex = property == null
+ ? entityTypeIdentifyingExpressionOffsets[mappingParameter] + (int)((ConstantExpression)methodCallExpression.Arguments[1]).Value
+ : _materializationContextBindings[mappingParameter][property];
var projection = _selectExpression.Projection[projectionIndex];
return CreateGetValueExpression(
_dataReaderParameter,
projectionIndex,
IsNullableProjection(projection),
- property.GetRelationalTypeMapping(),
+ projection.Expression.TypeMapping,
methodCallExpression.Type,
property);
}
diff --git a/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs
index 7b82675d12e..3799d0c3f9f 100644
--- a/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs
+++ b/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs
@@ -747,19 +747,60 @@ protected override Expression VisitTypeBinary(TypeBinaryExpression typeBinaryExp
if (derivedType != null)
{
var concreteEntityTypes = derivedType.GetConcreteDerivedTypesInclusive().ToList();
- var discriminatorColumn = BindProperty(entityReferenceExpression, entityType.GetDiscriminatorProperty());
-
- return concreteEntityTypes.Count == 1
- ? _sqlExpressionFactory.Equal(
- discriminatorColumn,
- _sqlExpressionFactory.Constant(concreteEntityTypes[0].GetDiscriminatorValue()))
- : (Expression)_sqlExpressionFactory.In(
- discriminatorColumn,
- _sqlExpressionFactory.Constant(concreteEntityTypes.Select(et => et.GetDiscriminatorValue()).ToList()),
- negated: false);
- }
+ var discriminatorProperty = entityType.GetDiscriminatorProperty();
+ if (discriminatorProperty == null)
+ {
+ // TPT
+ if (entityReferenceExpression.SubqueryEntity != null)
+ {
+ var entityShaper = (EntityShaperExpression)entityReferenceExpression.SubqueryEntity.ShaperExpression;
+ var entityProjection = (EntityProjectionExpression)Visit(entityShaper.ValueBufferExpression);
+ var subSelectExpression = (SelectExpression)entityReferenceExpression.SubqueryEntity.QueryExpression;
+
+ var predicate = entityProjection.EntityTypeIdentifyingExpressionMap
+ .Where(kvp => concreteEntityTypes.Contains(kvp.Key))
+ .Select(kvp => kvp.Value)
+ .Aggregate((l, r) => _sqlExpressionFactory.OrElse(l, r));
+
+ subSelectExpression.ApplyPredicate(predicate);
+ subSelectExpression.ReplaceProjectionMapping(new Dictionary());
+ if (subSelectExpression.Limit == null
+ && subSelectExpression.Offset == null)
+ {
+ subSelectExpression.ClearOrdering();
+ }
+
+ return _sqlExpressionFactory.Exists(subSelectExpression, false);
+ }
+
+ if (entityReferenceExpression.ParameterEntity != null)
+ {
+ var entityProjection = (EntityProjectionExpression)Visit(
+ entityReferenceExpression.ParameterEntity.ValueBufferExpression);
+
+ return entityProjection.EntityTypeIdentifyingExpressionMap
+ .Where(kvp => concreteEntityTypes.Contains(kvp.Key))
+ .Select(kvp => kvp.Value)
+ .Aggregate((l, r) => _sqlExpressionFactory.OrElse(l, r));
+ }
+ }
+ else
+ {
+ var discriminatorColumn = BindProperty(entityReferenceExpression, discriminatorProperty);
- return _sqlExpressionFactory.Constant(false);
+ if (discriminatorColumn != null)
+ {
+ return concreteEntityTypes.Count == 1
+ ? _sqlExpressionFactory.Equal(
+ discriminatorColumn,
+ _sqlExpressionFactory.Constant(concreteEntityTypes[0].GetDiscriminatorValue()))
+ : (Expression)_sqlExpressionFactory.In(
+ discriminatorColumn,
+ _sqlExpressionFactory.Constant(concreteEntityTypes.Select(et => et.GetDiscriminatorValue()).ToList()),
+ negated: false);
+ }
+ }
+ }
}
return null;
diff --git a/src/EFCore.Relational/Query/SqlExpressionFactory.cs b/src/EFCore.Relational/Query/SqlExpressionFactory.cs
index 0a2aaa7875e..23adc434eaf 100644
--- a/src/EFCore.Relational/Query/SqlExpressionFactory.cs
+++ b/src/EFCore.Relational/Query/SqlExpressionFactory.cs
@@ -757,7 +757,7 @@ public virtual SelectExpression Select(IEntityType entityType)
{
Check.NotNull(entityType, nameof(entityType));
- var selectExpression = new SelectExpression(entityType);
+ var selectExpression = new SelectExpression(entityType, this);
AddConditions(selectExpression, entityType);
return selectExpression;
@@ -801,7 +801,7 @@ private void AddSelfConditions(SelectExpression selectExpression, IEntityType en
}
// Add conditions if dependent sharing table with principal
- table ??= entityType.GetViewOrTableMappings().SingleOrDefault()?.Table;
+ table ??= entityType.GetViewOrTableMappings().FirstOrDefault()?.Table;
if (table != null
&& table.GetRowInternalForeignKeys(entityType).Any()
&& !discriminatorAdded)
@@ -814,7 +814,7 @@ private void AddConditions(SelectExpression selectExpression, IEntityType entity
{
AddSelfConditions(selectExpression, entityType, table);
// Add inner join to principal if table sharing
- table ??= entityType.GetViewOrTableMappings().SingleOrDefault()?.Table;
+ table ??= entityType.GetViewOrTableMappings().FirstOrDefault()?.Table;
if (table != null)
{
var linkingFks = table.GetRowInternalForeignKeys(entityType);
@@ -828,7 +828,7 @@ private void AddConditions(SelectExpression selectExpression, IEntityType entity
}
else
{
- var dependentSelectExpression = new SelectExpression(entityType);
+ var dependentSelectExpression = new SelectExpression(entityType, this);
AddSelfConditions(dependentSelectExpression, entityType, table);
AddInnerJoin(dependentSelectExpression, foreignKey, table);
selectExpression.ApplyUnion(dependentSelectExpression, distinct: true);
@@ -843,8 +843,8 @@ private void AddInnerJoin(SelectExpression selectExpression, IForeignKey foreign
var outerIsPrincipal = foreignKey.PrincipalEntityType.IsAssignableFrom(outerEntityProjection.EntityType);
var innerSelect = outerIsPrincipal
- ? new SelectExpression(foreignKey.DeclaringEntityType)
- : new SelectExpression(foreignKey.PrincipalEntityType);
+ ? new SelectExpression(foreignKey.DeclaringEntityType, this)
+ : new SelectExpression(foreignKey.PrincipalEntityType, this);
if (outerIsPrincipal)
{
@@ -944,7 +944,7 @@ private void AddOptionalDependentConditions(
// other dependents.
foreach (var referencingFk in entityType.GetReferencingForeignKeys())
{
- var otherSelectExpression = new SelectExpression(entityType);
+ var otherSelectExpression = new SelectExpression(entityType, this);
var sameTable = table.GetRowInternalForeignKeys(referencingFk.DeclaringEntityType).Any();
AddInnerJoin(
diff --git a/src/EFCore.Relational/Query/SqlExpressions/ColumnExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/ColumnExpression.cs
index 902ee50976e..0feada9e848 100644
--- a/src/EFCore.Relational/Query/SqlExpressions/ColumnExpression.cs
+++ b/src/EFCore.Relational/Query/SqlExpressions/ColumnExpression.cs
@@ -24,18 +24,13 @@ namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions
// Class is sealed because there are no public/protected constructors. Can be unsealed if this is changed.
public sealed class ColumnExpression : SqlExpression
{
- internal ColumnExpression(IProperty property, TableExpressionBase table, bool nullable)
+ internal ColumnExpression(IProperty property, IColumnBase column, TableExpressionBase table, bool nullable)
: this(
- property.GetTableColumnMappings().Cast().Concat(property.GetViewColumnMappings())
- .FirstOrDefault()?.Column.Name // TODO: this should take table into account
- ?? property.GetColumnName(),
+ column?.Name ?? property.GetColumnName(),
table,
property.ClrType,
property.GetRelationalTypeMapping(),
- nullable
- || (property.GetTableColumnMappings().Cast().Concat(property.GetViewColumnMappings())
- .FirstOrDefault()?.Column.IsNullable // TODO: this should take table into account
- ?? property.IsColumnNullable()))
+ nullable || (column?.IsNullable ?? property.IsColumnNullable()))
{
}
diff --git a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs
index 3853994b059..66e63739b06 100644
--- a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs
+++ b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs
@@ -118,9 +118,116 @@ internal SelectExpression(SqlExpression projection)
}
}
- internal SelectExpression(IEntityType entityType)
- : this(entityType, new TableExpression(entityType.GetViewOrTableMappings().Single().Table))
+ internal SelectExpression(IEntityType entityType, ISqlExpressionFactory sqlExpressionFactory)
+ : base(null)
{
+ if ((entityType.BaseType == null && !entityType.GetDirectlyDerivedTypes().Any())
+ || entityType.GetDiscriminatorProperty() != null)
+ {
+ // Key-less entities or TPH
+ var table = entityType.GetViewOrTableMappings().Single().Table;
+ var tableExpression = new TableExpression(table);
+ _tables.Add(tableExpression);
+
+ var propertyExpressions = new Dictionary();
+ foreach (var property in GetAllPropertiesInHierarchy(entityType))
+ {
+ propertyExpressions[property] = GetColumn(
+ property, property.DeclaringEntityType, table, tableExpression, nullable: false);
+ }
+
+ var entityProjection = new EntityProjectionExpression(entityType, propertyExpressions);
+ _projectionMapping[new ProjectionMember()] = entityProjection;
+
+ if (entityType.FindPrimaryKey() != null)
+ {
+ foreach (var property in entityType.FindPrimaryKey().Properties)
+ {
+ _identifier.Add((propertyExpressions[property], property.GetKeyValueComparer()));
+ }
+ }
+ }
+ else
+ {
+ // TPT
+ var keyProperties = entityType.FindPrimaryKey().Properties;
+ List joinColumns = null;
+ var tables = new List();
+ var columns = new Dictionary();
+ foreach (var baseType in entityType.GetAllBaseTypesInclusive())
+ {
+ var table = baseType.GetViewOrTableMappings().Single(m => !tables.Contains(m.Table)).Table;
+ tables.Add(table);
+ var tableExpression = new TableExpression(table);
+ foreach (var property in baseType.GetDeclaredProperties())
+ {
+ columns[property] = GetColumn(property, baseType, table, tableExpression, nullable: false);
+ }
+
+ if (_tables.Count == 0)
+ {
+ _tables.Add(tableExpression);
+ joinColumns = new List();
+ foreach (var property in keyProperties)
+ {
+ var columnExpression = columns[property];
+ joinColumns.Add(columnExpression);
+ _identifier.Add((columnExpression, property.GetKeyValueComparer()));
+ }
+ }
+ else
+ {
+ var innerColumns = keyProperties.Select(p => GetColumn(p, baseType, table, tableExpression, nullable: false));
+
+ var joinPredicate = joinColumns.Zip(innerColumns, (l, r) => sqlExpressionFactory.Equal(l, r))
+ .Aggregate((l, r) => sqlExpressionFactory.AndAlso(l, r));
+
+ var joinExpression = new InnerJoinExpression(tableExpression, joinPredicate);
+ _tables.Add(joinExpression);
+ }
+ }
+
+ var discriminatorExpressions = new Dictionary();
+
+ foreach (var derivedType in entityType.GetDerivedTypes())
+ {
+ var table = derivedType.GetViewOrTableMappings().Single(m => !tables.Contains(m.Table)).Table;
+ tables.Add(table);
+ var tableExpression = new TableExpression(table);
+ foreach (var property in derivedType.GetDeclaredProperties())
+ {
+ columns[property] = GetColumn(property, derivedType, table, tableExpression, nullable: true);
+ }
+
+ var keyColumns = keyProperties.Select(p => GetColumn(p, derivedType, table, tableExpression, nullable: true)).ToArray();
+
+ if (!derivedType.IsAbstract())
+ {
+ discriminatorExpressions[derivedType] = sqlExpressionFactory.IsNotNull(keyColumns[0]);
+ }
+
+ var joinPredicate = joinColumns.Zip(keyColumns, (l, r) => sqlExpressionFactory.Equal(l, r))
+ .Aggregate((l, r) => sqlExpressionFactory.AndAlso(l, r));
+
+ var joinExpression = new LeftJoinExpression(tableExpression, joinPredicate);
+ _tables.Add(joinExpression);
+ }
+
+ var entityProjection = new EntityProjectionExpression(entityType, columns, discriminatorExpressions);
+ _projectionMapping[new ProjectionMember()] = entityProjection;
+ }
+
+ static ColumnExpression GetColumn(
+ IProperty property, IEntityType currentEntityType, ITableBase table, TableExpression tableExpression, bool nullable)
+ {
+ var column = table is ITable
+ ? (IColumnBase)property.GetTableColumnMappings().Single(cm => cm.TableMapping.Table == table
+ && cm.TableMapping.EntityType == currentEntityType).Column
+ : property.GetViewColumnMappings().Single(cm => cm.TableMapping.Table == table
+ && cm.TableMapping.EntityType == currentEntityType).Column;
+
+ return new ColumnExpression(property, column, tableExpression, nullable: nullable);
+ }
}
internal SelectExpression(IEntityType entityType, TableExpressionBase tableExpression)
@@ -128,7 +235,13 @@ internal SelectExpression(IEntityType entityType, TableExpressionBase tableExpre
{
_tables.Add(tableExpression);
- var entityProjection = new EntityProjectionExpression(entityType, tableExpression, false);
+ var propertyExpressions = new Dictionary();
+ foreach (var property in GetAllPropertiesInHierarchy(entityType))
+ {
+ propertyExpressions[property] = new ColumnExpression(property, null, tableExpression, nullable: false);
+ }
+
+ var entityProjection = new EntityProjectionExpression(entityType, propertyExpressions);
_projectionMapping[new ProjectionMember()] = entityProjection;
if (entityType.FindPrimaryKey() != null)
@@ -176,12 +289,19 @@ public void ApplyProjection()
if (keyValuePair.Value is EntityProjectionExpression entityProjection)
{
var map = new Dictionary();
-
foreach (var property in GetAllPropertiesInHierarchy(entityProjection.EntityType))
{
map[property] = AddToProjection(entityProjection.BindProperty(property));
}
+ if (entityProjection.EntityTypeIdentifyingExpressionMap != null)
+ {
+ foreach (var kvp in entityProjection.EntityTypeIdentifyingExpressionMap)
+ {
+ AddToProjection(kvp.Value, $"Is{kvp.Key.ShortName()}");
+ }
+ }
+
result[keyValuePair.Key] = Constant(map);
}
else
@@ -254,19 +374,23 @@ private int AddToProjection(SqlExpression sqlExpression, string alias)
return existingIndex;
}
- var baseAlias = alias ?? (sqlExpression as ColumnExpression)?.Name ?? (Alias != null ? "c" : null);
- var currentAlias = baseAlias ?? "";
- if (Alias != null
- && baseAlias != null)
+ var baseAlias = !string.IsNullOrEmpty(alias)
+ ? alias
+ : (sqlExpression as ColumnExpression)?.Name ?? (Alias != null ? "c" : null);
+ if (Alias != null)
{
var counter = 0;
+ Check.DebugAssert(baseAlias != null, "baseAlias should be non-null since this is a subquery.");
+
+ var currentAlias = baseAlias;
while (_projection.Any(pe => string.Equals(pe.Alias, currentAlias, StringComparison.OrdinalIgnoreCase)))
{
currentAlias = $"{baseAlias}{counter++}";
}
+ baseAlias = currentAlias;
}
- _projection.Add(new ProjectionExpression(sqlExpression, currentAlias));
+ _projection.Add(new ProjectionExpression(sqlExpression, baseAlias ?? ""));
return _projection.Count - 1;
}
@@ -288,6 +412,14 @@ public IDictionary AddToProjection([NotNull] EntityProjectionExp
dictionary[property] = AddToProjection(entityProjection.BindProperty(property));
}
+ if (entityProjection.EntityTypeIdentifyingExpressionMap != null)
+ {
+ foreach (var kvp in entityProjection.EntityTypeIdentifyingExpressionMap)
+ {
+ AddToProjection(kvp.Value, $"Is{kvp.Key.ShortName()}");
+ }
+ }
+
_entityProjectionCache[entityProjection] = dictionary;
}
@@ -704,7 +836,7 @@ private void ApplySetOperation(SetOperationType setOperationType, SelectExpressi
if (joinedMapping.Value1 is EntityProjectionExpression entityProjection1
&& joinedMapping.Value2 is EntityProjectionExpression entityProjection2)
{
- HandleEntityMapping(joinedMapping.Key, select1, entityProjection1, select2, entityProjection2);
+ HandleEntityProjection(joinedMapping.Key, select1, entityProjection1, select2, entityProjection2);
continue;
}
@@ -752,7 +884,7 @@ private void ApplySetOperation(SetOperationType setOperationType, SelectExpressi
_tables.Clear();
_tables.Add(setExpression);
- void HandleEntityMapping(
+ void HandleEntityProjection(
ProjectionMember projectionMember,
SelectExpression select1, EntityProjectionExpression projection1,
SelectExpression select2, EntityProjectionExpression projection2)
@@ -765,15 +897,43 @@ void HandleEntityMapping(
var propertyExpressions = new Dictionary();
foreach (var property in GetAllPropertiesInHierarchy(projection1.EntityType))
{
- propertyExpressions[property] = AddSetOperationColumnProjections(
+ propertyExpressions[property] = GenerateColumnProjection(
select1, projection1.BindProperty(property),
select2, projection2.BindProperty(property));
}
- _projectionMapping[projectionMember] = new EntityProjectionExpression(projection1.EntityType, propertyExpressions);
+ Dictionary entityTypeIdentifyingExpressionMap = null;
+ if (projection1.EntityTypeIdentifyingExpressionMap != null)
+ {
+ entityTypeIdentifyingExpressionMap = new Dictionary();
+ // Both types will have same key since their entity types are same.
+ foreach (var kvp in projection1.EntityTypeIdentifyingExpressionMap)
+ {
+ var entityType = kvp.Key;
+ entityTypeIdentifyingExpressionMap[entityType] = GenerateEntityTypeIdentifyingExpression(
+ select1, kvp.Value, select2, projection2.EntityTypeIdentifyingExpressionMap[entityType],
+ $"Is{entityType.ShortName()}");
+ }
+ }
+
+ _projectionMapping[projectionMember] = new EntityProjectionExpression(
+ projection1.EntityType, propertyExpressions, entityTypeIdentifyingExpressionMap);
}
- ColumnExpression AddSetOperationColumnProjections(
+ ColumnExpression GenerateEntityTypeIdentifyingExpression(
+ SelectExpression select1, SqlExpression expression1,
+ SelectExpression select2, SqlExpression expression2,
+ string alias)
+ {
+ var innerProjection1 = new ProjectionExpression(expression1, alias);
+ var innerProjection2 = new ProjectionExpression(expression2, alias);
+ select1._projection.Add(innerProjection1);
+ select2._projection.Add(innerProjection2);
+
+ return new ColumnExpression(innerProjection1, setExpression);
+ }
+
+ ColumnExpression GenerateColumnProjection(
SelectExpression select1, ColumnExpression column1,
SelectExpression select2, ColumnExpression column2)
{
@@ -846,13 +1006,13 @@ public IDictionary PushdownIntoSubquery()
// Projections may be present if added by lifting SingleResult/Enumerable in projection through join
if (_projection.Any())
{
- var projections = _projection.Select(pe => pe.Expression).ToList();
+ var projections = _projection.ToList();
_projection.Clear();
foreach (var projection in projections)
{
- var outerColumn = subquery.GenerateOuterColumn(projection);
+ var outerColumn = subquery.GenerateOuterColumn(projection.Expression, projection.Alias);
AddToProjection(outerColumn);
- projectionMap[projection] = outerColumn;
+ projectionMap[projection.Expression] = outerColumn;
}
}
@@ -960,7 +1120,23 @@ EntityProjectionExpression LiftEntityProjectionFromSubquery(EntityProjectionExpr
propertyExpressions[property] = outerColumn;
}
- var newEntityProjection = new EntityProjectionExpression(entityProjection.EntityType, propertyExpressions);
+ Dictionary entityTypeIdentifyingExpressionMap = null;
+ if (entityProjection.EntityTypeIdentifyingExpressionMap != null)
+ {
+ entityTypeIdentifyingExpressionMap = new Dictionary();
+ foreach (var entityTypeIdentifyingExpression in entityProjection.EntityTypeIdentifyingExpressionMap)
+ {
+ var innerProjection = entityTypeIdentifyingExpression.Value;
+ var outerColumn = subquery.GenerateOuterColumn(
+ innerProjection, $"Is{entityTypeIdentifyingExpression.Key.ShortName()}");
+ projectionMap[innerProjection] = outerColumn;
+ entityTypeIdentifyingExpressionMap[entityTypeIdentifyingExpression.Key] = outerColumn;
+ }
+ }
+
+ var newEntityProjection = new EntityProjectionExpression(
+ entityProjection.EntityType, propertyExpressions, entityTypeIdentifyingExpressionMap);
+
// Also lift nested entity projections
foreach (var navigation in entityProjection.EntityType
.GetAllBaseTypes().Concat(entityProjection.EntityType.GetDerivedTypesInclusive())
diff --git a/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs b/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs
index ffe97d4bacc..386b256e7bc 100644
--- a/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs
+++ b/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs
@@ -501,12 +501,6 @@ private Expression MaterializeEntity(
entityShaperExpression.MaterializationCondition.Body)));
var concreteEntityTypes = entityType.GetConcreteDerivedTypesInclusive().ToArray();
- var discriminatorProperty = entityType.GetDiscriminatorProperty();
- if (discriminatorProperty == null
- && concreteEntityTypes.Length > 1)
- {
- concreteEntityTypes = new [] { entityType };
- }
var switchCases = new SwitchCase[concreteEntityTypes.Length];
for (var i = 0; i < concreteEntityTypes.Length; i++)
diff --git a/test/EFCore.Relational.Specification.Tests/Query/TPTInheritanceQueryFixture.cs b/test/EFCore.Relational.Specification.Tests/Query/TPTInheritanceQueryFixture.cs
index 5a4a8ad2f97..0c7b5fc3159 100644
--- a/test/EFCore.Relational.Specification.Tests/Query/TPTInheritanceQueryFixture.cs
+++ b/test/EFCore.Relational.Specification.Tests/Query/TPTInheritanceQueryFixture.cs
@@ -43,11 +43,11 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con
modelBuilder.Entity().Property(e => e.SugarGrams).HasColumnName("SugarGrams");
modelBuilder.Entity().Property(e => e.CaffeineGrams).HasColumnName("CaffeineGrams");
- // Keyless entities are mapped to TPH
- modelBuilder.Entity().HasNoKey().ToQuery(
- () => context.Set().FromSqlRaw("SELECT * FROM Animals"));
- modelBuilder.Entity().HasDiscriminator().HasValue("Kiwi");
- modelBuilder.Entity().HasDiscriminator().HasValue("Eagle");
+ // Keyless entities are mapped to TPH so ignoring them
+ modelBuilder.Ignore();
+ modelBuilder.Ignore();
+ modelBuilder.Ignore();
+ modelBuilder.Ignore();
}
}
}
diff --git a/test/EFCore.Relational.Specification.Tests/Query/TPTInheritanceQueryTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/TPTInheritanceQueryTestBase.cs
index 9941e982c91..4992fca6b21 100644
--- a/test/EFCore.Relational.Specification.Tests/Query/TPTInheritanceQueryTestBase.cs
+++ b/test/EFCore.Relational.Specification.Tests/Query/TPTInheritanceQueryTestBase.cs
@@ -16,232 +16,19 @@ public TPTInheritanceQueryTestBase(TFixture fixture)
{
}
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Byte_enum_value_constant_used_in_projection(bool async)
- {
- return base.Byte_enum_value_constant_used_in_projection(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Can_filter_all_animals(bool async)
- {
- return base.Can_filter_all_animals(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Can_include_animals(bool async)
- {
- return base.Can_include_animals(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Can_include_prey(bool async)
- {
- return base.Can_include_prey(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override void Can_insert_update_delete()
- {
- base.Can_insert_update_delete();
- }
+ // Keyless entities does not have TPT
+ public override Task Can_query_all_animal_views(bool async) => Task.CompletedTask;
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Can_query_all_animals(bool async)
- {
- return base.Can_query_all_animals(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Can_query_all_animal_views(bool async)
- {
- return base.Can_query_all_animal_views(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Can_query_all_birds(bool async)
- {
- return base.Can_query_all_birds(async);
- }
+ // TPT does not have discriminator
+ public override Task Discriminator_used_when_projection_over_derived_type(bool async) => Task.CompletedTask;
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Can_query_all_plants(bool async)
- {
- return base.Can_query_all_plants(async);
- }
+ // TPT does not have discriminator
+ public override Task Discriminator_used_when_projection_over_derived_type2(bool async) => Task.CompletedTask;
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Can_query_all_types_when_shared_column(bool async)
- {
- return base.Can_query_all_types_when_shared_column(async);
- }
+ // TPT does not have discriminator
+ public override Task Discriminator_used_when_projection_over_of_type(bool async) => Task.CompletedTask;
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Can_query_just_kiwis(bool async)
- {
- return base.Can_query_just_kiwis(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Can_query_just_roses(bool async)
- {
- return base.Can_query_just_roses(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Can_query_when_shared_column(bool async)
- {
- return base.Can_query_when_shared_column(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Can_use_backwards_is_animal(bool async)
- {
- return base.Can_use_backwards_is_animal(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Can_use_backwards_of_type_animal(bool async)
- {
- return base.Can_use_backwards_of_type_animal(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Can_use_is_kiwi(bool async)
- {
- return base.Can_use_is_kiwi(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Can_use_is_kiwi_in_projection(bool async)
- {
- return base.Can_use_is_kiwi_in_projection(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Can_use_is_kiwi_with_other_predicate(bool async)
- {
- return base.Can_use_is_kiwi_with_other_predicate(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Can_use_of_type_animal(bool async)
- {
- return base.Can_use_of_type_animal(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Can_use_of_type_bird(bool async)
- {
- return base.Can_use_of_type_bird(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Can_use_of_type_bird_first(bool async)
- {
- return base.Can_use_of_type_bird_first(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Can_use_of_type_bird_predicate(bool async)
- {
- return base.Can_use_of_type_bird_predicate(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Can_use_of_type_bird_with_projection(bool async)
- {
- return base.Can_use_of_type_bird_with_projection(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Can_use_of_type_kiwi(bool async)
- {
- return base.Can_use_of_type_kiwi(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Can_use_of_type_kiwi_where_north_on_derived_property(bool async)
- {
- return base.Can_use_of_type_kiwi_where_north_on_derived_property(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Can_use_of_type_kiwi_where_south_on_derived_property(bool async)
- {
- return base.Can_use_of_type_kiwi_where_south_on_derived_property(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Can_use_of_type_rose(bool async)
- {
- return base.Can_use_of_type_rose(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Discriminator_used_when_projection_over_derived_type(bool async)
- {
- return base.Discriminator_used_when_projection_over_derived_type(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Discriminator_used_when_projection_over_derived_type2(bool async)
- {
- return base.Discriminator_used_when_projection_over_derived_type2(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Discriminator_used_when_projection_over_of_type(bool async)
- {
- return base.Discriminator_used_when_projection_over_of_type(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Discriminator_with_cast_in_shadow_property(bool async)
- {
- return base.Discriminator_with_cast_in_shadow_property(async);
- }
-
- [ConditionalFact(Skip = "Issue#2266")]
- public override void Member_access_on_intermediate_type_works()
- {
- base.Member_access_on_intermediate_type_works();
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task OfType_Union_OfType(bool async)
- {
- return base.OfType_Union_OfType(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task OfType_Union_subquery(bool async)
- {
- return base.OfType_Union_subquery(async);
- }
-
- [ConditionalFact(Skip = "Issue#2266")]
- public override void Setting_foreign_key_to_a_different_type_throws()
- {
- base.Setting_foreign_key_to_a_different_type_throws();
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Subquery_OfType(bool async)
- {
- return base.Subquery_OfType(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Union_entity_equality(bool async)
- {
- return base.Union_entity_equality(async);
- }
-
- [ConditionalTheory(Skip = "Issue#2266")]
- public override Task Union_siblings_with_duplicate_property_in_subquery(bool async)
- {
- return base.Union_siblings_with_duplicate_property_in_subquery(async);
- }
+ // TPT does not have discriminator
+ public override Task Discriminator_with_cast_in_shadow_property(bool async) => Task.CompletedTask;
}
}
diff --git a/test/EFCore.Relational.Specification.Tests/Query/TPTRelationshipsQueryTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/TPTRelationshipsQueryTestBase.cs
index b8b2fefa817..92132f56b9f 100644
--- a/test/EFCore.Relational.Specification.Tests/Query/TPTRelationshipsQueryTestBase.cs
+++ b/test/EFCore.Relational.Specification.Tests/Query/TPTRelationshipsQueryTestBase.cs
@@ -13,230 +13,5 @@ protected TPTRelationshipsQueryTestBase(TFixture fixture)
: base(fixture)
{
}
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Changes_in_derived_related_entities_are_detected()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_reference_with_inheritance()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_reference_with_inheritance_reverse()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_self_reference_with_inheritance()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_self_reference_with_inheritance_reverse()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_reference_with_inheritance_with_filter()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_reference_with_inheritance_with_filter_reverse()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_reference_without_inheritance()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_reference_without_inheritance_reverse()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_reference_without_inheritance_with_filter()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_reference_without_inheritance_with_filter_reverse()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_collection_with_inheritance()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_collection_with_inheritance_reverse()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_collection_with_inheritance_with_filter()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_collection_with_inheritance_with_filter_reverse()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_collection_without_inheritance()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_collection_without_inheritance_reverse()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_collection_without_inheritance_with_filter()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_collection_without_inheritance_with_filter_reverse()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_reference_with_inheritance_on_derived1()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_reference_with_inheritance_on_derived2()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_reference_with_inheritance_on_derived4()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_reference_with_inheritance_on_derived_reverse()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_reference_with_inheritance_on_derived_with_filter1()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_reference_with_inheritance_on_derived_with_filter2()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_reference_with_inheritance_on_derived_with_filter4()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_reference_with_inheritance_on_derived_with_filter_reverse()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_reference_without_inheritance_on_derived1()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_reference_without_inheritance_on_derived2()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_reference_without_inheritance_on_derived_reverse()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_collection_with_inheritance_on_derived1()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_collection_with_inheritance_on_derived2()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_collection_with_inheritance_on_derived3()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Include_collection_with_inheritance_on_derived_reverse()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Nested_include_with_inheritance_reference_reference()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Nested_include_with_inheritance_reference_reference_on_base()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Nested_include_with_inheritance_reference_reference_reverse()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Nested_include_with_inheritance_reference_collection()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Nested_include_with_inheritance_reference_collection_on_base()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Nested_include_with_inheritance_reference_collection_reverse()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Nested_include_with_inheritance_collection_reference()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Nested_include_with_inheritance_collection_reference_reverse()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Nested_include_with_inheritance_collection_collection()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Nested_include_with_inheritance_collection_collection_reverse()
- {
- }
-
- [ConditionalFact(Skip = "Issue #2266")]
- public override void Nested_include_collection_reference_on_non_entity_base()
- {
- }
}
}
diff --git a/test/EFCore.Relational.Specification.Tests/TPTTableSplittingTestBase.cs b/test/EFCore.Relational.Specification.Tests/TPTTableSplittingTestBase.cs
new file mode 100644
index 00000000000..a631a00e852
--- /dev/null
+++ b/test/EFCore.Relational.Specification.Tests/TPTTableSplittingTestBase.cs
@@ -0,0 +1,554 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Linq;
+using Microsoft.EntityFrameworkCore.Diagnostics;
+using Microsoft.EntityFrameworkCore.TestModels.TransportationModel;
+using Microsoft.EntityFrameworkCore.TestUtilities;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Xunit;
+using Xunit.Abstractions;
+
+// ReSharper disable InconsistentNaming
+namespace Microsoft.EntityFrameworkCore
+{
+ public abstract class TPTTableSplittingTestBase
+ {
+ protected TPTTableSplittingTestBase(ITestOutputHelper testOutputHelper)
+ {
+ TestSqlLoggerFactory = (TestSqlLoggerFactory)TestStoreFactory.CreateListLoggerFactory(_ => true);
+ //TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper);
+ }
+
+ [ConditionalFact]
+ public virtual void Can_update_just_dependents()
+ {
+ using (CreateTestStore(OnModelCreating))
+ {
+ Operator firstOperator;
+ Engine firstEngine;
+ using (var context = CreateContext())
+ {
+ firstOperator = context.Set().OrderBy(o => o.VehicleName).First();
+ firstOperator.Name += "1";
+ firstEngine = context.Set().OrderBy(o => o.VehicleName).First();
+ firstEngine.Description += "1";
+
+ context.SaveChanges();
+
+ Assert.Empty(context.ChangeTracker.Entries().Where(e => e.State != EntityState.Unchanged));
+ }
+
+ using (var context = CreateContext())
+ {
+ Assert.Equal(firstOperator.Name, context.Set().OrderBy(o => o.VehicleName).First().Name);
+ Assert.Equal(firstEngine.Description, context.Set().OrderBy(o => o.VehicleName).First().Description);
+ }
+ }
+ }
+
+ [ConditionalFact]
+ public virtual void Can_query_shared()
+ {
+ using (CreateTestStore(OnModelCreating))
+ {
+ using var context = CreateContext();
+ Assert.Equal(5, context.Set().ToList().Count);
+ }
+ }
+
+ [ConditionalFact]
+ public virtual void Can_query_shared_nonhierarchy()
+ {
+ using (CreateTestStore(
+ modelBuilder =>
+ {
+ OnModelCreating(modelBuilder);
+ modelBuilder.Ignore();
+ }))
+ {
+ using var context = CreateContext();
+ Assert.Equal(5, context.Set().ToList().Count);
+ }
+ }
+
+ [ConditionalFact]
+ public virtual void Can_query_shared_nonhierarchy_with_nonshared_dependent()
+ {
+ using (CreateTestStore(
+ modelBuilder =>
+ {
+ OnModelCreating(modelBuilder);
+ modelBuilder.Ignore();
+ modelBuilder.Entity().ToTable("OperatorDetails");
+ }))
+ {
+ using var context = CreateContext();
+ Assert.Equal(5, context.Set().ToList().Count);
+ }
+ }
+
+ [ConditionalFact]
+ public virtual void Can_query_shared_derived_hierarchy()
+ {
+ using (CreateTestStore(OnModelCreating))
+ {
+ using var context = CreateContext();
+ Assert.Equal(2, context.Set().ToList().Count);
+ }
+ }
+
+ [ConditionalFact]
+ public virtual void Can_query_shared_derived_nonhierarchy()
+ {
+ using (CreateTestStore(
+ modelBuilder =>
+ {
+ OnModelCreating(modelBuilder);
+ modelBuilder.Ignore();
+ }))
+ {
+ using var context = CreateContext();
+ Assert.Equal(2, context.Set().ToList().Count);
+ }
+ }
+
+ [ConditionalFact]
+ public virtual void Can_query_shared_derived_nonhierarchy_all_required()
+ {
+ using (CreateTestStore(
+ modelBuilder =>
+ {
+ OnModelCreating(modelBuilder);
+ modelBuilder.Ignore();
+ modelBuilder.Entity(
+ eb =>
+ {
+ eb.Property(t => t.Capacity).IsRequired();
+ eb.Property(t => t.FuelType).IsRequired();
+ });
+ }))
+ {
+ using var context = CreateContext();
+ Assert.Equal(2, context.Set().ToList().Count);
+ }
+ }
+
+ [ConditionalFact]
+ public virtual void Can_use_with_redundant_relationships()
+ {
+ Test_roundtrip(OnModelCreating);
+ }
+
+ [ConditionalFact]
+ public virtual void Can_use_with_chained_relationships()
+ {
+ Test_roundtrip(
+ modelBuilder =>
+ {
+ OnModelCreating(modelBuilder);
+ modelBuilder.Entity(eb => { eb.Ignore(e => e.Vehicle); });
+ });
+ }
+
+ [ConditionalFact]
+ public virtual void Can_use_with_fanned_relationships()
+ {
+ Test_roundtrip(
+ modelBuilder =>
+ {
+ OnModelCreating(modelBuilder);
+
+ modelBuilder.Entity().HasOne(e => e.FuelTank).WithOne().HasForeignKey(e => e.VehicleName);
+ modelBuilder.Entity(eb => eb.Ignore(e => e.Engine));
+ });
+ }
+
+ [ConditionalFact]
+ public virtual void Can_share_required_columns()
+ {
+ using (CreateTestStore(
+ modelBuilder =>
+ {
+ OnModelCreating(modelBuilder);
+ modelBuilder.Entity(
+ vb =>
+ {
+ vb.Property(v => v.SeatingCapacity).HasColumnName("SeatingCapacity");
+ });
+ modelBuilder.Entity(
+ cb =>
+ {
+ cb.Property("SeatingCapacity").HasColumnName("SeatingCapacity");
+ });
+
+ modelBuilder.Entity().HasOne(e => e.FuelTank).WithOne().HasForeignKey(e => e.VehicleName);
+ modelBuilder.Entity(
+ fb =>
+ {
+ fb.Ignore(f => f.Engine);
+ });
+ }, seed: false))
+ {
+ using (var context = CreateContext())
+ {
+ var scooterEntry = context.Add(
+ new PoweredVehicle
+ {
+ Name = "Electric scooter",
+ SeatingCapacity = 1,
+ Engine = new Engine()
+ });
+
+ scooterEntry.Reference(v => v.Engine).TargetEntry.Property("SeatingCapacity").CurrentValue = 1;
+
+ context.SaveChanges();
+ }
+
+ using (var context = CreateContext())
+ {
+ var scooter = context.Set().Include(v => v.Engine).Single(v => v.Name == "Electric scooter");
+
+ Assert.Equal(scooter.SeatingCapacity, context.Entry(scooter.Engine).Property("SeatingCapacity").CurrentValue);
+ }
+ }
+ }
+
+ protected void Test_roundtrip(Action onModelCreating)
+ {
+ using (CreateTestStore(onModelCreating))
+ {
+ using var context = CreateContext();
+ context.AssertSeeded();
+ }
+ }
+
+ [ConditionalFact(Skip = "Issue#21497")]
+ public virtual void Can_manipulate_entities_sharing_row_independently()
+ {
+ using (CreateTestStore(
+ modelBuilder =>
+ {
+ OnModelCreating(modelBuilder);
+ modelBuilder.Entity().HasOne(e => e.FuelTank).WithOne().HasForeignKey(e => e.VehicleName);
+ modelBuilder.Entity(eb => eb.Ignore(e => e.Engine));
+ }))
+ {
+ PoweredVehicle streetcar;
+ using (var context = CreateContext())
+ {
+ streetcar = context.Set().Include(v => v.Engine)
+ .Single(v => v.Name == "1984 California Car");
+
+ Assert.Null(streetcar.Engine);
+
+ streetcar.Engine = new Engine { Description = "Streetcar engine" };
+
+ context.SaveChanges();
+ }
+
+ using (var context = CreateContext())
+ {
+ var streetcarFromStore = context.Set().Include(v => v.Engine).AsNoTracking()
+ .Single(v => v.Name == "1984 California Car");
+
+ Assert.Equal("Streetcar engine", streetcarFromStore.Engine.Description);
+
+ streetcarFromStore.Engine.Description = "Line";
+
+ context.Update(streetcarFromStore);
+ context.SaveChanges();
+ }
+
+ using (var context = CreateContext())
+ {
+ var streetcarFromStore = context.Set().Include(v => v.Engine)
+ .Single(v => v.Name == "1984 California Car");
+
+ Assert.Equal("Line", streetcarFromStore.Engine.Description);
+
+ streetcarFromStore.SeatingCapacity = 40;
+ streetcarFromStore.Engine.Description = "Streetcar engine";
+
+ context.SaveChanges();
+ }
+
+ using (var context = CreateContext())
+ {
+ var streetcarFromStore = context.Set().Include(v => v.Engine).AsNoTracking()
+ .Single(v => v.Name == "1984 California Car");
+
+ Assert.Equal(40, streetcarFromStore.SeatingCapacity);
+ Assert.Equal("Streetcar engine", streetcarFromStore.Engine.Description);
+
+ context.Remove(streetcarFromStore.Engine);
+
+ context.SaveChanges();
+ }
+
+ using (var context = CreateContext())
+ {
+ var streetcarFromStore = context.Set().Include(v => v.Engine).AsNoTracking()
+ .Single(v => v.Name == "1984 California Car");
+
+ Assert.Null(streetcarFromStore.Engine);
+
+ context.Remove(streetcarFromStore);
+
+ context.SaveChanges();
+ }
+
+ using (var context = CreateContext())
+ {
+ Assert.Null(context.Set().AsNoTracking().SingleOrDefault(v => v.Name == "1984 California Car"));
+ Assert.Null(context.Set().AsNoTracking().SingleOrDefault(e => e.VehicleName == "1984 California Car"));
+ }
+ }
+ }
+
+ [ConditionalFact]
+ public virtual void Can_insert_dependent_with_just_one_parent()
+ {
+ using (CreateTestStore(OnModelCreating))
+ {
+ using var context = CreateContext();
+ context.Add(
+ new PoweredVehicle
+ {
+ Name = "Fuel transport",
+ SeatingCapacity = 1,
+ Operator = new LicensedOperator { Name = "Jack Jackson", LicenseType = "Class A CDC" }
+ });
+ context.Add(
+ new FuelTank
+ {
+ Capacity = "10000 l",
+ FuelType = "Gas",
+ VehicleName = "Fuel transport"
+ });
+
+ context.SaveChanges();
+ }
+ }
+
+ [ConditionalFact(Skip = "Issue#21497")]
+ public virtual void Can_change_dependent_instance_non_derived()
+ {
+ using (CreateTestStore(
+ modelBuilder =>
+ {
+ OnModelCreating(modelBuilder);
+ modelBuilder.Entity().ToTable("Engines");
+ modelBuilder.Entity(
+ eb =>
+ {
+ eb.ToTable("FuelTanks");
+ eb.HasOne(e => e.Engine)
+ .WithOne(e => e.FuelTank)
+ .HasForeignKey(e => e.VehicleName)
+ .OnDelete(DeleteBehavior.Restrict);
+ });
+ modelBuilder.Ignore();
+ modelBuilder.Ignore();
+ }))
+ {
+ using (var context = CreateContext())
+ {
+ var bike = context.Vehicles.Include(v => v.Operator).Single(v => v.Name == "Trek Pro Fit Madone 6 Series");
+
+ bike.Operator = new Operator { Name = "Chris Horner" };
+
+ context.ChangeTracker.DetectChanges();
+
+ bike.Operator = new LicensedOperator { Name = "repairman", LicenseType = "Repair" };
+
+ TestSqlLoggerFactory.Clear();
+ context.SaveChanges();
+
+ Assert.Empty(context.ChangeTracker.Entries().Where(e => e.State != EntityState.Unchanged));
+ }
+
+ using (var context = CreateContext())
+ {
+ var bike = context.Vehicles.Include(v => v.Operator).Single(v => v.Name == "Trek Pro Fit Madone 6 Series");
+ Assert.Equal("repairman", bike.Operator.Name);
+ Assert.Equal("Repair", ((LicensedOperator)bike.Operator).LicenseType);
+ }
+ }
+ }
+
+ [ConditionalFact]
+ public virtual void Can_change_principal_instance_non_derived()
+ {
+ using (CreateTestStore(
+ modelBuilder =>
+ {
+ OnModelCreating(modelBuilder);
+ modelBuilder.Entity().ToTable("Engines");
+ modelBuilder.Entity(
+ eb =>
+ {
+ eb.ToTable("FuelTanks");
+ eb.HasOne(e => e.Engine)
+ .WithOne(e => e.FuelTank)
+ .HasForeignKey(e => e.VehicleName)
+ .OnDelete(DeleteBehavior.Restrict);
+ });
+ modelBuilder.Ignore();
+ modelBuilder.Ignore();
+ }))
+ {
+ using (var context = CreateContext())
+ {
+ var bike = context.Vehicles.Single(v => v.Name == "Trek Pro Fit Madone 6 Series");
+
+ var newBike = new Vehicle
+ {
+ Name = "Trek Pro Fit Madone 6 Series",
+ Operator = bike.Operator,
+ SeatingCapacity = 2
+ };
+
+ context.Remove(bike);
+ context.Add(newBike);
+
+ TestSqlLoggerFactory.Clear();
+ context.SaveChanges();
+
+ Assert.Empty(context.ChangeTracker.Entries().Where(e => e.State != EntityState.Unchanged));
+ }
+
+ using (var context = CreateContext())
+ {
+ var bike = context.Vehicles.Include(v => v.Operator).Single(v => v.Name == "Trek Pro Fit Madone 6 Series");
+
+ Assert.Equal(2, bike.SeatingCapacity);
+ Assert.NotNull(bike.Operator);
+ }
+ }
+ }
+
+ [ConditionalFact(Skip = "Issue#21497")]
+ public virtual void Can_change_principal_and_dependent_instance_non_derived()
+ {
+ using (CreateTestStore(
+ modelBuilder =>
+ {
+ OnModelCreating(modelBuilder);
+ modelBuilder.Entity().ToTable("Engines");
+ modelBuilder.Entity(
+ eb =>
+ {
+ eb.ToTable("FuelTanks");
+ eb.HasOne(e => e.Engine)
+ .WithOne(e => e.FuelTank)
+ .HasForeignKey(e => e.VehicleName)
+ .OnDelete(DeleteBehavior.Restrict);
+ });
+ modelBuilder.Ignore();
+ modelBuilder.Ignore();
+ }))
+ {
+ using (var context = CreateContext())
+ {
+ var bike = context.Vehicles.Include(v => v.Operator).Single(v => v.Name == "Trek Pro Fit Madone 6 Series");
+
+ var newBike = new Vehicle
+ {
+ Name = "Trek Pro Fit Madone 6 Series",
+ Operator = new LicensedOperator { Name = "repairman", LicenseType = "Repair" },
+ SeatingCapacity = 2
+ };
+
+ context.Remove(bike);
+ context.Add(newBike);
+
+ TestSqlLoggerFactory.Clear();
+ context.SaveChanges();
+
+ Assert.Empty(context.ChangeTracker.Entries().Where(e => e.State != EntityState.Unchanged));
+ }
+
+ using (var context = CreateContext())
+ {
+ var bike = context.Vehicles.Include(v => v.Operator).Single(v => v.Name == "Trek Pro Fit Madone 6 Series");
+ Assert.Equal(2, bike.SeatingCapacity);
+ Assert.Equal("repairman", bike.Operator.Name);
+ Assert.Equal("Repair", ((LicensedOperator)bike.Operator).LicenseType);
+ }
+ }
+ }
+
+ protected readonly string DatabaseName = "TPTTableSplittingTest";
+ protected TestStore TestStore { get; set; }
+ protected abstract ITestStoreFactory TestStoreFactory { get; }
+ protected IServiceProvider ServiceProvider { get; set; }
+ protected TestSqlLoggerFactory TestSqlLoggerFactory { get; }
+
+ protected void AssertSql(params string[] expected)
+ => TestSqlLoggerFactory.AssertBaseline(expected);
+
+ protected virtual void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ modelBuilder.Entity().ToTable("Vehicles");
+ modelBuilder.Entity().ToTable("PoweredVehicles");
+
+ modelBuilder.Entity().ToTable("Vehicles")
+ .Property("RequiredInt").HasDefaultValue(0);
+ modelBuilder.Entity().ToTable("LicensedOperators");
+
+ modelBuilder.Entity().ToTable("Vehicles");
+
+ modelBuilder.Entity().ToTable("PoweredVehicles")
+ .HasOne(e => e.Vehicle).WithOne(e => e.Engine).OnDelete(DeleteBehavior.NoAction);
+ modelBuilder.Entity().ToTable("CombustionEngines");
+ modelBuilder.Entity().ToTable("IntermittentCombustionEngines");
+ modelBuilder.Entity().ToTable("ContinuousCombustionEngines");
+ modelBuilder.Entity().ToTable("SolidRockets").Ignore(e => e.SolidFuelTank);
+
+ modelBuilder.Entity().ToTable("CombustionEngines")
+ .HasOne(e => e.Vehicle).WithOne().OnDelete(DeleteBehavior.NoAction);
+ modelBuilder.Entity().ToTable("SolidFuelTanks").Ignore(e => e.Rocket);
+ }
+
+ protected TestStore CreateTestStore(Action onModelCreating, bool seed = true)
+ {
+ TestStore = TestStoreFactory.Create(DatabaseName);
+
+ ServiceProvider = TestStoreFactory.AddProviderServices(new ServiceCollection())
+ .AddSingleton(TestModelSource.GetFactory(onModelCreating))
+ .AddSingleton(TestSqlLoggerFactory)
+ .BuildServiceProvider(validateScopes: true);
+
+ TestStore.Initialize(
+ ServiceProvider, CreateContext, c =>
+ {
+ if (seed)
+ {
+ ((TransportationContext)c).Seed();
+ }
+ });
+
+ TestSqlLoggerFactory.Clear();
+
+ return TestStore;
+ }
+
+ protected virtual DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
+ => builder
+ .EnableSensitiveDataLogging()
+ .ConfigureWarnings(
+ b => b.Default(WarningBehavior.Throw)
+ .Log(CoreEventId.SensitiveDataLoggingEnabledWarning)
+ .Log(CoreEventId.PossibleUnintendedReferenceComparisonWarning));
+
+ protected virtual TransportationContext CreateContext()
+ {
+ var options = AddOptions(TestStore.AddProviderOptions(new DbContextOptionsBuilder()))
+ .UseInternalServiceProvider(ServiceProvider).Options;
+ return new TransportationContext(options);
+ }
+ }
+}
diff --git a/test/EFCore.Specification.Tests/Query/InheritanceQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/InheritanceQueryTestBase.cs
index b30dc493a12..0f57c4114df 100644
--- a/test/EFCore.Specification.Tests/Query/InheritanceQueryTestBase.cs
+++ b/test/EFCore.Specification.Tests/Query/InheritanceQueryTestBase.cs
@@ -404,10 +404,6 @@ public virtual void Can_insert_update_delete()
});
}
- protected virtual void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction)
- {
- }
-
[ConditionalTheory(Skip = "Issue#16298")]
[MemberData(nameof(IsAsyncData))]
public virtual Task Union_siblings_with_duplicate_property_in_subquery(bool async)
@@ -527,8 +523,24 @@ public virtual void Member_access_on_intermediate_type_works()
Assert.Equal("Great spotted kiwi", kiwi.Name);
}
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Is_operator_on_result_of_FirstOrDefault(bool async)
+ {
+ return AssertQuery(
+ async,
+ ss => ss.Set()
+ .Where(a => ss.Set().FirstOrDefault(a1 => a1.Name == "Great spotted kiwi") is Kiwi)
+ .OrderBy(a => a.Species),
+ assertOrder: true);
+ }
+
protected InheritanceContext CreateContext() => Fixture.CreateContext();
+ protected virtual void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction)
+ {
+ }
+
protected virtual bool EnforcesFkConstraints => true;
protected virtual void ClearLog()
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs
index aa765286fa9..c45a0c89f95 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs
@@ -3987,10 +3987,10 @@ public override async Task Correlated_collections_inner_subquery_selector_refere
await base.Correlated_collections_inner_subquery_selector_references_outer_qsre(async);
AssertSql(
- @"SELECT [g].[FullName], [g].[Nickname], [g].[SquadId], [t].[FullName], [t].[FullName0], [t].[Nickname], [t].[SquadId]
+ @"SELECT [g].[FullName], [g].[Nickname], [g].[SquadId], [t].[ReportName], [t].[OfficerName], [t].[Nickname], [t].[SquadId]
FROM [Gears] AS [g]
OUTER APPLY (
- SELECT [g0].[FullName], [g].[FullName] AS [FullName0], [g0].[Nickname], [g0].[SquadId]
+ SELECT [g0].[FullName] AS [ReportName], [g].[FullName] AS [OfficerName], [g0].[Nickname], [g0].[SquadId]
FROM [Gears] AS [g0]
WHERE ([g].[Nickname] = [g0].[LeaderNickname]) AND ([g].[SquadId] = [g0].[LeaderSquadId])
) AS [t]
@@ -4003,10 +4003,10 @@ public override async Task Correlated_collections_inner_subquery_predicate_refer
await base.Correlated_collections_inner_subquery_predicate_references_outer_qsre(async);
AssertSql(
- @"SELECT [g].[FullName], [g].[Nickname], [g].[SquadId], [t].[FullName], [t].[Nickname], [t].[SquadId]
+ @"SELECT [g].[FullName], [g].[Nickname], [g].[SquadId], [t].[ReportName], [t].[Nickname], [t].[SquadId]
FROM [Gears] AS [g]
OUTER APPLY (
- SELECT [g0].[FullName], [g0].[Nickname], [g0].[SquadId]
+ SELECT [g0].[FullName] AS [ReportName], [g0].[Nickname], [g0].[SquadId]
FROM [Gears] AS [g0]
WHERE ([g].[FullName] <> N'Foo') AND (([g].[Nickname] = [g0].[LeaderNickname]) AND ([g].[SquadId] = [g0].[LeaderSquadId]))
) AS [t]
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/IncompleteMappingInheritanceQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/IncompleteMappingInheritanceQuerySqlServerTest.cs
index 7c6cc3ac73a..55e73f4982f 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/IncompleteMappingInheritanceQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/IncompleteMappingInheritanceQuerySqlServerTest.cs
@@ -525,6 +525,20 @@ INNER JOIN (
WHERE [a].[Discriminator] = N'Eagle'");
}
+ public override async Task Is_operator_on_result_of_FirstOrDefault(bool async)
+ {
+ await base.Is_operator_on_result_of_FirstOrDefault(async);
+
+ AssertSql(
+ @"SELECT [a].[Species], [a].[CountryId], [a].[Discriminator], [a].[Name], [a].[EagleId], [a].[IsFlightless], [a].[Group], [a].[FoundOn]
+FROM [Animal] AS [a]
+WHERE [a].[Discriminator] IN (N'Eagle', N'Kiwi') AND ((
+ SELECT TOP(1) [a0].[Discriminator]
+ FROM [Animal] AS [a0]
+ WHERE [a0].[Discriminator] IN (N'Eagle', N'Kiwi') AND ([a0].[Name] = N'Great spotted kiwi')) = N'Kiwi')
+ORDER BY [a].[Species]");
+ }
+
protected override void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction)
=> facade.UseTransaction(transaction.GetDbTransaction());
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/InheritanceQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/InheritanceQuerySqlServerTest.cs
index aea867ae87d..a944a75780d 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/InheritanceQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/InheritanceQuerySqlServerTest.cs
@@ -501,6 +501,20 @@ INNER JOIN (
WHERE [a].[Discriminator] = N'Eagle'");
}
+ public override async Task Is_operator_on_result_of_FirstOrDefault(bool async)
+ {
+ await base.Is_operator_on_result_of_FirstOrDefault(async);
+
+ AssertSql(
+ @"SELECT [a].[Species], [a].[CountryId], [a].[Discriminator], [a].[Name], [a].[EagleId], [a].[IsFlightless], [a].[Group], [a].[FoundOn]
+FROM [Animal] AS [a]
+WHERE (
+ SELECT TOP(1) [a0].[Discriminator]
+ FROM [Animal] AS [a0]
+ WHERE [a0].[Name] = N'Great spotted kiwi') = N'Kiwi'
+ORDER BY [a].[Species]");
+ }
+
protected override void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction)
=> facade.UseTransaction(transaction.GetDbTransaction());
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs
index 347fd6645e4..680334a23d6 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs
@@ -1,4 +1,4 @@
-// Copyright (c) .NET Foundation. All rights reserved.
+// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
@@ -4451,13 +4451,13 @@ public override async Task Complex_nested_query_doesnt_try_binding_to_grandparen
await base.Complex_nested_query_doesnt_try_binding_to_grandparent_when_parent_returns_complex_result(async);
AssertSql(
- @"SELECT [c].[CustomerID], [t].[c], [t].[CustomerID], [t].[OrderID]
+ @"SELECT [c].[CustomerID], [t].[InnerOrder], [t].[Id], [t].[OrderID]
FROM [Customers] AS [c]
OUTER APPLY (
SELECT (
SELECT COUNT(*)
FROM [Orders] AS [o]
- WHERE [c].[CustomerID] = [o].[CustomerID]) AS [c], [c].[CustomerID], [o0].[OrderID]
+ WHERE [c].[CustomerID] = [o].[CustomerID]) AS [InnerOrder], [c].[CustomerID] AS [Id], [o0].[OrderID]
FROM [Orders] AS [o0]
WHERE [c].[CustomerID] = [o0].[CustomerID]
) AS [t]
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs
index 57fc1c1c949..96f85cfdca1 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs
@@ -325,12 +325,12 @@ public override void Select_nested_collection_multi_level()
base.Select_nested_collection_multi_level();
AssertSql(
- @"SELECT [c].[CustomerID], [t0].[OrderDate], [t0].[OrderID]
+ @"SELECT [c].[CustomerID], [t0].[Date], [t0].[OrderID]
FROM [Customers] AS [c]
LEFT JOIN (
- SELECT [t].[OrderDate], [t].[OrderID], [t].[CustomerID]
+ SELECT [t].[Date], [t].[OrderID], [t].[CustomerID]
FROM (
- SELECT [o].[OrderDate], [o].[OrderID], [o].[CustomerID], ROW_NUMBER() OVER(PARTITION BY [o].[CustomerID] ORDER BY [o].[OrderID]) AS [row]
+ SELECT [o].[OrderDate] AS [Date], [o].[OrderID], [o].[CustomerID], ROW_NUMBER() OVER(PARTITION BY [o].[CustomerID] ORDER BY [o].[OrderID]) AS [row]
FROM [Orders] AS [o]
WHERE [o].[OrderID] < 10500
) AS [t]
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs
index 42b71fa451c..e3dea35c976 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs
@@ -6361,7 +6361,7 @@ private class Activity12456
#region Issue15137
[ConditionalFact]
- public virtual async Task Run_something()
+ public virtual async Task Max_in_multi_level_nested_subquery()
{
using (CreateDatabase15137())
{
@@ -6391,8 +6391,8 @@ public virtual async Task Run_something()
})
.SingleAsync();
- AssertSql(
- @"SELECT [t0].[Id], [t1].[Id], [t1].[Id0], [t1].[Id1], [t1].[c]
+ AssertSql(
+ @"SELECT [t0].[Id], [t1].[Id], [t1].[Id0], [t1].[Id1], [t1].[IsPastTradeDeadline]
FROM (
SELECT TOP(2) [t].[Id]
FROM [Trades] AS [t]
@@ -6404,7 +6404,7 @@ SELECT MAX([d].[GameNumber])
FROM [DbGame] AS [d]
WHERE [d2].[Id] IS NOT NULL AND ([d2].[Id] = [d].[SeasonId])), 0) > 10 THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
- END AS [c], [d0].[DbTradeId]
+ END AS [IsPastTradeDeadline], [d0].[DbTradeId]
FROM [DbTradeAsset] AS [d0]
INNER JOIN [DbContract] AS [d1] ON [d0].[ContractId] = [d1].[Id]
LEFT JOIN [DbSeason] AS [d2] ON [d1].[SeasonId] = [d2].[Id]
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPTInheritanceQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPTInheritanceQuerySqlServerTest.cs
index e45970c608f..3cfe7634ff5 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/TPTInheritanceQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPTInheritanceQuerySqlServerTest.cs
@@ -1,6 +1,9 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage;
using Xunit.Abstractions;
// ReSharper disable InconsistentNaming
@@ -14,5 +17,628 @@ public TPTInheritanceQuerySqlServerTest(TPTInheritanceQuerySqlServerFixture fixt
Fixture.TestSqlLoggerFactory.Clear();
//Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper);
}
+
+ public override async Task Byte_enum_value_constant_used_in_projection(bool async)
+ {
+ await base.Byte_enum_value_constant_used_in_projection(async);
+
+ AssertSql(
+ @"SELECT CASE
+ WHEN [b].[IsFlightless] = CAST(1 AS bit) THEN CAST(0 AS tinyint)
+ ELSE CAST(1 AS tinyint)
+END
+FROM [Animals] AS [a]
+INNER JOIN [Birds] AS [b] ON [a].[Species] = [b].[Species]
+INNER JOIN [Kiwi] AS [k] ON [a].[Species] = [k].[Species]");
+ }
+
+ public override async Task Can_filter_all_animals(bool async)
+ {
+ await base.Can_filter_all_animals(async);
+
+ AssertSql(
+ @"SELECT [a].[Species], [a].[CountryId], [a].[Name], [b].[EagleId], [b].[IsFlightless], [e].[Group], [k].[FoundOn], CASE
+ WHEN [e].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsEagle], CASE
+ WHEN [k].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsKiwi]
+FROM [Animals] AS [a]
+LEFT JOIN [Birds] AS [b] ON [a].[Species] = [b].[Species]
+LEFT JOIN [Eagle] AS [e] ON [a].[Species] = [e].[Species]
+LEFT JOIN [Kiwi] AS [k] ON [a].[Species] = [k].[Species]
+WHERE [a].[Name] = N'Great spotted kiwi'
+ORDER BY [a].[Species]");
+ }
+
+ public override async Task Can_include_animals(bool async)
+ {
+ await base.Can_include_animals(async);
+
+ AssertSql(
+ @"SELECT [c].[Id], [c].[Name], [t].[Species], [t].[CountryId], [t].[Name], [t].[EagleId], [t].[IsFlightless], [t].[Group], [t].[FoundOn], [t].[IsEagle], [t].[IsKiwi]
+FROM [Country] AS [c]
+LEFT JOIN (
+ SELECT [a].[Species], [a].[CountryId], [a].[Name], [b].[EagleId], [b].[IsFlightless], [e].[Group], [k].[FoundOn], CASE
+ WHEN [e].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsEagle], CASE
+ WHEN [k].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsKiwi]
+ FROM [Animals] AS [a]
+ LEFT JOIN [Birds] AS [b] ON [a].[Species] = [b].[Species]
+ LEFT JOIN [Eagle] AS [e] ON [a].[Species] = [e].[Species]
+ LEFT JOIN [Kiwi] AS [k] ON [a].[Species] = [k].[Species]
+) AS [t] ON [c].[Id] = [t].[CountryId]
+ORDER BY [c].[Name], [c].[Id], [t].[Species]");
+ }
+
+ public override async Task Can_include_prey(bool async)
+ {
+ await base.Can_include_prey(async);
+
+ AssertSql(
+ @"SELECT [t].[Species], [t].[CountryId], [t].[Name], [t].[EagleId], [t].[IsFlightless], [t].[Group], [t0].[Species], [t0].[CountryId], [t0].[Name], [t0].[EagleId], [t0].[IsFlightless], [t0].[Group], [t0].[FoundOn], [t0].[IsEagle], [t0].[IsKiwi]
+FROM (
+ SELECT TOP(2) [a].[Species], [a].[CountryId], [a].[Name], [b].[EagleId], [b].[IsFlightless], [e].[Group]
+ FROM [Animals] AS [a]
+ INNER JOIN [Birds] AS [b] ON [a].[Species] = [b].[Species]
+ INNER JOIN [Eagle] AS [e] ON [a].[Species] = [e].[Species]
+) AS [t]
+LEFT JOIN (
+ SELECT [a0].[Species], [a0].[CountryId], [a0].[Name], [b0].[EagleId], [b0].[IsFlightless], [e0].[Group], [k].[FoundOn], CASE
+ WHEN [e0].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsEagle], CASE
+ WHEN [k].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsKiwi]
+ FROM [Animals] AS [a0]
+ INNER JOIN [Birds] AS [b0] ON [a0].[Species] = [b0].[Species]
+ LEFT JOIN [Eagle] AS [e0] ON [a0].[Species] = [e0].[Species]
+ LEFT JOIN [Kiwi] AS [k] ON [a0].[Species] = [k].[Species]
+) AS [t0] ON [t].[Species] = [t0].[EagleId]
+ORDER BY [t].[Species], [t0].[Species]");
+ }
+
+ public override void Can_insert_update_delete()
+ {
+ base.Can_insert_update_delete();
+
+ AssertSql(
+ @"SELECT TOP(2) [c].[Id], [c].[Name]
+FROM [Countries] AS [c]
+WHERE [c].[Id] = 1",
+ //
+ @"@p0='Apteryx owenii' (Nullable = false) (Size = 100)
+@p1='1'
+@p2='Little spotted kiwi' (Size = 4000)
+
+SET NOCOUNT ON;
+INSERT INTO [Animals] ([Species], [CountryId], [Name])
+VALUES (@p0, @p1, @p2);",
+ //
+ @"@p0='Apteryx owenii' (Nullable = false) (Size = 100)
+@p1=NULL (Size = 100)
+@p2='True'
+
+SET NOCOUNT ON;
+INSERT INTO [Birds] ([Species], [EagleId], [IsFlightless])
+VALUES (@p0, @p1, @p2);",
+ //
+ @"@p0='Apteryx owenii' (Nullable = false) (Size = 100)
+@p1='0' (Size = 1)
+
+SET NOCOUNT ON;
+INSERT INTO [Kiwi] ([Species], [FoundOn])
+VALUES (@p0, @p1);",
+ //
+ @"SELECT TOP(2) [a].[Species], [a].[CountryId], [a].[Name], [b].[EagleId], [b].[IsFlightless], [k].[FoundOn]
+FROM [Animals] AS [a]
+INNER JOIN [Birds] AS [b] ON [a].[Species] = [b].[Species]
+INNER JOIN [Kiwi] AS [k] ON [a].[Species] = [k].[Species]
+WHERE [a].[Species] LIKE N'%owenii'",
+ //
+ @"@p1='Apteryx owenii' (Nullable = false) (Size = 100)
+@p0='Aquila chrysaetos canadensis' (Size = 100)
+
+SET NOCOUNT ON;
+UPDATE [Birds] SET [EagleId] = @p0
+WHERE [Species] = @p1;
+SELECT @@ROWCOUNT;",
+ //
+ @"SELECT TOP(2) [a].[Species], [a].[CountryId], [a].[Name], [b].[EagleId], [b].[IsFlightless], [k].[FoundOn]
+FROM [Animals] AS [a]
+INNER JOIN [Birds] AS [b] ON [a].[Species] = [b].[Species]
+INNER JOIN [Kiwi] AS [k] ON [a].[Species] = [k].[Species]
+WHERE [a].[Species] LIKE N'%owenii'",
+ //
+ @"@p0='Apteryx owenii' (Nullable = false) (Size = 100)
+
+SET NOCOUNT ON;
+DELETE FROM [Animals]
+WHERE [Species] = @p0;
+SELECT @@ROWCOUNT;",
+ //
+ @"@p0='Apteryx owenii' (Nullable = false) (Size = 100)
+
+SET NOCOUNT ON;
+DELETE FROM [Birds]
+WHERE [Species] = @p0;
+SELECT @@ROWCOUNT;",
+ //
+ @"@p0='Apteryx owenii' (Nullable = false) (Size = 100)
+
+SET NOCOUNT ON;
+DELETE FROM [Kiwi]
+WHERE [Species] = @p0;
+SELECT @@ROWCOUNT;",
+ //
+ @"SELECT COUNT(*)
+FROM [Animals] AS [a]
+INNER JOIN [Birds] AS [b] ON [a].[Species] = [b].[Species]
+INNER JOIN [Kiwi] AS [k] ON [a].[Species] = [k].[Species]
+WHERE [a].[Species] LIKE N'%owenii'");
+ }
+
+ public override async Task Can_query_all_animals(bool async)
+ {
+ await base.Can_query_all_animals(async);
+
+ AssertSql(
+ @"SELECT [a].[Species], [a].[CountryId], [a].[Name], [b].[EagleId], [b].[IsFlightless], [e].[Group], [k].[FoundOn], CASE
+ WHEN [e].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsEagle], CASE
+ WHEN [k].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsKiwi]
+FROM [Animals] AS [a]
+LEFT JOIN [Birds] AS [b] ON [a].[Species] = [b].[Species]
+LEFT JOIN [Eagle] AS [e] ON [a].[Species] = [e].[Species]
+LEFT JOIN [Kiwi] AS [k] ON [a].[Species] = [k].[Species]
+ORDER BY [a].[Species]");
+ }
+
+ public override async Task Can_query_all_birds(bool async)
+ {
+ await base.Can_query_all_birds(async);
+
+ AssertSql(
+ @"SELECT [a].[Species], [a].[CountryId], [a].[Name], [b].[EagleId], [b].[IsFlightless], [e].[Group], [k].[FoundOn], CASE
+ WHEN [e].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsEagle], CASE
+ WHEN [k].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsKiwi]
+FROM [Animals] AS [a]
+INNER JOIN [Birds] AS [b] ON [a].[Species] = [b].[Species]
+LEFT JOIN [Eagle] AS [e] ON [a].[Species] = [e].[Species]
+LEFT JOIN [Kiwi] AS [k] ON [a].[Species] = [k].[Species]
+ORDER BY [a].[Species]");
+ }
+
+ public override async Task Can_query_all_plants(bool async)
+ {
+ await base.Can_query_all_plants(async);
+
+ AssertSql(
+ @"SELECT [p].[Species], [p].[CountryId], [p].[Genus], [p].[Name], [r].[HasThorns], CASE
+ WHEN [d].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsDaisy], CASE
+ WHEN [r].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsRose]
+FROM [Plants] AS [p]
+LEFT JOIN [Flowers] AS [f] ON [p].[Species] = [f].[Species]
+LEFT JOIN [Daisies] AS [d] ON [p].[Species] = [d].[Species]
+LEFT JOIN [Roses] AS [r] ON [p].[Species] = [r].[Species]
+ORDER BY [p].[Species]");
+ }
+
+ public override async Task Can_query_all_types_when_shared_column(bool async)
+ {
+ await base.Can_query_all_types_when_shared_column(async);
+
+ AssertSql(
+ @"SELECT [d].[Id], [c].[CaffeineGrams], [c].[CokeCO2], [c].[SugarGrams], [l].[LiltCO2], [l].[SugarGrams], [t].[CaffeineGrams], [t].[HasMilk], CASE
+ WHEN [c].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsCoke], CASE
+ WHEN [l].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsLilt], CASE
+ WHEN [t].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsTea]
+FROM [Drinks] AS [d]
+LEFT JOIN [Coke] AS [c] ON [d].[Id] = [c].[Id]
+LEFT JOIN [Lilt] AS [l] ON [d].[Id] = [l].[Id]
+LEFT JOIN [Tea] AS [t] ON [d].[Id] = [t].[Id]");
+ }
+
+ public override async Task Can_query_just_kiwis(bool async)
+ {
+ await base.Can_query_just_kiwis(async);
+
+ AssertSql(
+ @"SELECT TOP(2) [a].[Species], [a].[CountryId], [a].[Name], [b].[EagleId], [b].[IsFlightless], [k].[FoundOn]
+FROM [Animals] AS [a]
+INNER JOIN [Birds] AS [b] ON [a].[Species] = [b].[Species]
+INNER JOIN [Kiwi] AS [k] ON [a].[Species] = [k].[Species]");
+ }
+
+ public override async Task Can_query_just_roses(bool async)
+ {
+ await base.Can_query_just_roses(async);
+
+ AssertSql(
+ @"SELECT TOP(2) [p].[Species], [p].[CountryId], [p].[Genus], [p].[Name], [r].[HasThorns]
+FROM [Plants] AS [p]
+INNER JOIN [Flowers] AS [f] ON [p].[Species] = [f].[Species]
+INNER JOIN [Roses] AS [r] ON [p].[Species] = [r].[Species]");
+ }
+
+ public override async Task Can_query_when_shared_column(bool async)
+ {
+ await base.Can_query_when_shared_column(async);
+
+ AssertSql(
+ @"SELECT TOP(2) [d].[Id], [c].[CaffeineGrams], [c].[CokeCO2], [c].[SugarGrams]
+FROM [Drinks] AS [d]
+INNER JOIN [Coke] AS [c] ON [d].[Id] = [c].[Id]",
+ //
+ @"SELECT TOP(2) [d].[Id], [l].[LiltCO2], [l].[SugarGrams]
+FROM [Drinks] AS [d]
+INNER JOIN [Lilt] AS [l] ON [d].[Id] = [l].[Id]",
+ //
+ @"SELECT TOP(2) [d].[Id], [t].[CaffeineGrams], [t].[HasMilk]
+FROM [Drinks] AS [d]
+INNER JOIN [Tea] AS [t] ON [d].[Id] = [t].[Id]");
+ }
+
+ public override async Task Can_use_backwards_is_animal(bool async)
+ {
+ await base.Can_use_backwards_is_animal(async);
+
+ AssertSql(
+ @"SELECT [a].[Species], [a].[CountryId], [a].[Name], [b].[EagleId], [b].[IsFlightless], [k].[FoundOn]
+FROM [Animals] AS [a]
+INNER JOIN [Birds] AS [b] ON [a].[Species] = [b].[Species]
+INNER JOIN [Kiwi] AS [k] ON [a].[Species] = [k].[Species]");
+ }
+
+ public override async Task Can_use_backwards_of_type_animal(bool async)
+ {
+ await base.Can_use_backwards_of_type_animal(async);
+
+ AssertSql(" ");
+ }
+
+ public override async Task Can_use_is_kiwi(bool async)
+ {
+ await base.Can_use_is_kiwi(async);
+
+ AssertSql(
+ @"SELECT [a].[Species], [a].[CountryId], [a].[Name], [b].[EagleId], [b].[IsFlightless], [e].[Group], [k].[FoundOn], CASE
+ WHEN [e].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsEagle], CASE
+ WHEN [k].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsKiwi]
+FROM [Animals] AS [a]
+LEFT JOIN [Birds] AS [b] ON [a].[Species] = [b].[Species]
+LEFT JOIN [Eagle] AS [e] ON [a].[Species] = [e].[Species]
+LEFT JOIN [Kiwi] AS [k] ON [a].[Species] = [k].[Species]
+WHERE [k].[Species] IS NOT NULL");
+ }
+
+ public override async Task Can_use_is_kiwi_in_projection(bool async)
+ {
+ await base.Can_use_is_kiwi_in_projection(async);
+
+ AssertSql(
+ @"SELECT CASE
+ WHEN [k].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END
+FROM [Animals] AS [a]
+LEFT JOIN [Birds] AS [b] ON [a].[Species] = [b].[Species]
+LEFT JOIN [Eagle] AS [e] ON [a].[Species] = [e].[Species]
+LEFT JOIN [Kiwi] AS [k] ON [a].[Species] = [k].[Species]");
+ }
+
+ public override async Task Can_use_is_kiwi_with_other_predicate(bool async)
+ {
+ await base.Can_use_is_kiwi_with_other_predicate(async);
+
+ AssertSql(
+ @"SELECT [a].[Species], [a].[CountryId], [a].[Name], [b].[EagleId], [b].[IsFlightless], [e].[Group], [k].[FoundOn], CASE
+ WHEN [e].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsEagle], CASE
+ WHEN [k].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsKiwi]
+FROM [Animals] AS [a]
+LEFT JOIN [Birds] AS [b] ON [a].[Species] = [b].[Species]
+LEFT JOIN [Eagle] AS [e] ON [a].[Species] = [e].[Species]
+LEFT JOIN [Kiwi] AS [k] ON [a].[Species] = [k].[Species]
+WHERE [k].[Species] IS NOT NULL AND ([a].[CountryId] = 1)");
+ }
+
+ public override async Task Can_use_of_type_animal(bool async)
+ {
+ await base.Can_use_of_type_animal(async);
+
+ AssertSql(
+ @"SELECT [a].[Species], [a].[CountryId], [a].[Name], [b].[EagleId], [b].[IsFlightless], [e].[Group], [k].[FoundOn], CASE
+ WHEN [e].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsEagle], CASE
+ WHEN [k].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsKiwi]
+FROM [Animals] AS [a]
+LEFT JOIN [Birds] AS [b] ON [a].[Species] = [b].[Species]
+LEFT JOIN [Eagle] AS [e] ON [a].[Species] = [e].[Species]
+LEFT JOIN [Kiwi] AS [k] ON [a].[Species] = [k].[Species]
+ORDER BY [a].[Species]");
+ }
+
+ public override async Task Can_use_of_type_bird(bool async)
+ {
+ await base.Can_use_of_type_bird(async);
+
+ AssertSql(
+ @"SELECT [a].[Species], [a].[CountryId], [a].[Name], [b].[EagleId], [b].[IsFlightless], [e].[Group], [k].[FoundOn], CASE
+ WHEN [e].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsEagle], CASE
+ WHEN [k].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsKiwi]
+FROM [Animals] AS [a]
+LEFT JOIN [Birds] AS [b] ON [a].[Species] = [b].[Species]
+LEFT JOIN [Eagle] AS [e] ON [a].[Species] = [e].[Species]
+LEFT JOIN [Kiwi] AS [k] ON [a].[Species] = [k].[Species]
+WHERE [e].[Species] IS NOT NULL OR [k].[Species] IS NOT NULL
+ORDER BY [a].[Species]");
+ }
+
+ public override async Task Can_use_of_type_bird_first(bool async)
+ {
+ await base.Can_use_of_type_bird_first(async);
+
+ AssertSql(
+ @"SELECT TOP(1) [a].[Species], [a].[CountryId], [a].[Name], [b].[EagleId], [b].[IsFlightless], [e].[Group], [k].[FoundOn], CASE
+ WHEN [e].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsEagle], CASE
+ WHEN [k].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsKiwi]
+FROM [Animals] AS [a]
+LEFT JOIN [Birds] AS [b] ON [a].[Species] = [b].[Species]
+LEFT JOIN [Eagle] AS [e] ON [a].[Species] = [e].[Species]
+LEFT JOIN [Kiwi] AS [k] ON [a].[Species] = [k].[Species]
+WHERE [e].[Species] IS NOT NULL OR [k].[Species] IS NOT NULL
+ORDER BY [a].[Species]");
+ }
+
+ public override async Task Can_use_of_type_bird_predicate(bool async)
+ {
+ await base.Can_use_of_type_bird_predicate(async);
+
+ AssertSql(
+ @"SELECT [a].[Species], [a].[CountryId], [a].[Name], [b].[EagleId], [b].[IsFlightless], [e].[Group], [k].[FoundOn], CASE
+ WHEN [e].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsEagle], CASE
+ WHEN [k].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsKiwi]
+FROM [Animals] AS [a]
+LEFT JOIN [Birds] AS [b] ON [a].[Species] = [b].[Species]
+LEFT JOIN [Eagle] AS [e] ON [a].[Species] = [e].[Species]
+LEFT JOIN [Kiwi] AS [k] ON [a].[Species] = [k].[Species]
+WHERE ([a].[CountryId] = 1) AND ([e].[Species] IS NOT NULL OR [k].[Species] IS NOT NULL)
+ORDER BY [a].[Species]");
+ }
+
+ public override async Task Can_use_of_type_bird_with_projection(bool async)
+ {
+ await base.Can_use_of_type_bird_with_projection(async);
+
+ AssertSql(
+ @"SELECT [b].[EagleId]
+FROM [Animals] AS [a]
+LEFT JOIN [Birds] AS [b] ON [a].[Species] = [b].[Species]
+LEFT JOIN [Eagle] AS [e] ON [a].[Species] = [e].[Species]
+LEFT JOIN [Kiwi] AS [k] ON [a].[Species] = [k].[Species]
+WHERE [e].[Species] IS NOT NULL OR [k].[Species] IS NOT NULL");
+ }
+
+ public override async Task Can_use_of_type_kiwi(bool async)
+ {
+ await base.Can_use_of_type_kiwi(async);
+
+ AssertSql(
+ @"SELECT [a].[Species], [a].[CountryId], [a].[Name], [b].[EagleId], [b].[IsFlightless], [k].[FoundOn]
+FROM [Animals] AS [a]
+LEFT JOIN [Birds] AS [b] ON [a].[Species] = [b].[Species]
+LEFT JOIN [Eagle] AS [e] ON [a].[Species] = [e].[Species]
+LEFT JOIN [Kiwi] AS [k] ON [a].[Species] = [k].[Species]
+WHERE [k].[Species] IS NOT NULL");
+ }
+
+ public override async Task Can_use_of_type_kiwi_where_north_on_derived_property(bool async)
+ {
+ await base.Can_use_of_type_kiwi_where_north_on_derived_property(async);
+
+ AssertSql(
+ @"SELECT [a].[Species], [a].[CountryId], [a].[Name], [b].[EagleId], [b].[IsFlightless], [k].[FoundOn]
+FROM [Animals] AS [a]
+LEFT JOIN [Birds] AS [b] ON [a].[Species] = [b].[Species]
+LEFT JOIN [Eagle] AS [e] ON [a].[Species] = [e].[Species]
+LEFT JOIN [Kiwi] AS [k] ON [a].[Species] = [k].[Species]
+WHERE [k].[Species] IS NOT NULL AND ([k].[FoundOn] = CAST(0 AS tinyint))");
+ }
+
+ public override async Task Can_use_of_type_kiwi_where_south_on_derived_property(bool async)
+ {
+ await base.Can_use_of_type_kiwi_where_south_on_derived_property(async);
+
+ AssertSql(
+ @"SELECT [a].[Species], [a].[CountryId], [a].[Name], [b].[EagleId], [b].[IsFlightless], [k].[FoundOn]
+FROM [Animals] AS [a]
+LEFT JOIN [Birds] AS [b] ON [a].[Species] = [b].[Species]
+LEFT JOIN [Eagle] AS [e] ON [a].[Species] = [e].[Species]
+LEFT JOIN [Kiwi] AS [k] ON [a].[Species] = [k].[Species]
+WHERE [k].[Species] IS NOT NULL AND ([k].[FoundOn] = CAST(1 AS tinyint))");
+ }
+
+ public override async Task Can_use_of_type_rose(bool async)
+ {
+ await base.Can_use_of_type_rose(async);
+
+ AssertSql(
+ @"SELECT [p].[Species], [p].[CountryId], [p].[Genus], [p].[Name], [r].[HasThorns]
+FROM [Plants] AS [p]
+LEFT JOIN [Flowers] AS [f] ON [p].[Species] = [f].[Species]
+LEFT JOIN [Daisies] AS [d] ON [p].[Species] = [d].[Species]
+LEFT JOIN [Roses] AS [r] ON [p].[Species] = [r].[Species]
+WHERE [r].[Species] IS NOT NULL");
+ }
+
+ public override void Member_access_on_intermediate_type_works()
+ {
+ base.Member_access_on_intermediate_type_works();
+
+ AssertSql(
+ @"SELECT [a].[Name]
+FROM [Animals] AS [a]
+INNER JOIN [Birds] AS [b] ON [a].[Species] = [b].[Species]
+INNER JOIN [Kiwi] AS [k] ON [a].[Species] = [k].[Species]
+ORDER BY [a].[Name]");
+ }
+
+ public override async Task OfType_Union_OfType(bool async)
+ {
+ await base.OfType_Union_OfType(async);
+
+ AssertSql(" ");
+ }
+
+ public override async Task OfType_Union_subquery(bool async)
+ {
+ await base.OfType_Union_subquery(async);
+
+ AssertSql(" ");
+ }
+
+ public override void Setting_foreign_key_to_a_different_type_throws()
+ {
+ base.Setting_foreign_key_to_a_different_type_throws();
+
+ AssertSql(
+ @"SELECT TOP(2) [a].[Species], [a].[CountryId], [a].[Name], [b].[EagleId], [b].[IsFlightless], [k].[FoundOn]
+FROM [Animals] AS [a]
+INNER JOIN [Birds] AS [b] ON [a].[Species] = [b].[Species]
+INNER JOIN [Kiwi] AS [k] ON [a].[Species] = [k].[Species]",
+ //
+ @"@p0='Haliaeetus leucocephalus' (Nullable = false) (Size = 100)
+@p1='0'
+@p2='Bald eagle' (Size = 4000)
+
+SET NOCOUNT ON;
+INSERT INTO [Animals] ([Species], [CountryId], [Name])
+VALUES (@p0, @p1, @p2);");
+ }
+
+ public override async Task Subquery_OfType(bool async)
+ {
+ await base.Subquery_OfType(async);
+
+ AssertSql(
+ @"@__p_0='5'
+
+SELECT DISTINCT [t].[Species], [t].[CountryId], [t].[Name], [t].[EagleId], [t].[IsFlightless], [t].[FoundOn]
+FROM (
+ SELECT TOP(@__p_0) [a].[Species], [a].[CountryId], [a].[Name], [b].[EagleId], [b].[IsFlightless], [e].[Group], [k].[FoundOn], CASE
+ WHEN [e].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsEagle], CASE
+ WHEN [k].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsKiwi]
+ FROM [Animals] AS [a]
+ INNER JOIN [Birds] AS [b] ON [a].[Species] = [b].[Species]
+ LEFT JOIN [Eagle] AS [e] ON [a].[Species] = [e].[Species]
+ LEFT JOIN [Kiwi] AS [k] ON [a].[Species] = [k].[Species]
+) AS [t]
+WHERE [t].[IsKiwi] = CAST(1 AS bit)");
+ }
+
+ public override async Task Union_entity_equality(bool async)
+ {
+ await base.Union_entity_equality(async);
+
+ AssertSql(" ");
+ }
+
+ public override async Task Union_siblings_with_duplicate_property_in_subquery(bool async)
+ {
+ await base.Union_siblings_with_duplicate_property_in_subquery(async);
+
+ AssertSql(" ");
+ }
+
+ public override async Task Is_operator_on_result_of_FirstOrDefault(bool async)
+ {
+ await base.Is_operator_on_result_of_FirstOrDefault(async);
+
+ AssertSql(
+ @"SELECT [a].[Species], [a].[CountryId], [a].[Name], [b].[EagleId], [b].[IsFlightless], [e].[Group], [k].[FoundOn], CASE
+ WHEN [e].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsEagle], CASE
+ WHEN [k].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsKiwi]
+FROM [Animals] AS [a]
+LEFT JOIN [Birds] AS [b] ON [a].[Species] = [b].[Species]
+LEFT JOIN [Eagle] AS [e] ON [a].[Species] = [e].[Species]
+LEFT JOIN [Kiwi] AS [k] ON [a].[Species] = [k].[Species]
+WHERE EXISTS (
+ SELECT 1
+ FROM (
+ SELECT TOP(1) [a0].[Species], [a0].[CountryId], [a0].[Name], [b0].[EagleId], [b0].[IsFlightless], [e0].[Group], [k0].[FoundOn], CASE
+ WHEN [e0].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsEagle], CASE
+ WHEN [k0].[Species] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsKiwi]
+ FROM [Animals] AS [a0]
+ LEFT JOIN [Birds] AS [b0] ON [a0].[Species] = [b0].[Species]
+ LEFT JOIN [Eagle] AS [e0] ON [a0].[Species] = [e0].[Species]
+ LEFT JOIN [Kiwi] AS [k0] ON [a0].[Species] = [k0].[Species]
+ WHERE [a0].[Name] = N'Great spotted kiwi'
+ ) AS [t]
+ WHERE [t].[IsKiwi] = CAST(1 AS bit))
+ORDER BY [a].[Species]");
+ }
+
+ protected override void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction)
+ => facade.UseTransaction(transaction.GetDbTransaction());
+
+ private void AssertSql(params string[] expected)
+ => Fixture.TestSqlLoggerFactory.AssertBaseline(expected);
}
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPTRelationshipsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPTRelationshipsQuerySqlServerTest.cs
index d87c538eb59..bfe91888e2e 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/TPTRelationshipsQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPTRelationshipsQuerySqlServerTest.cs
@@ -16,6 +16,1049 @@ public TPTRelationshipsQuerySqlServerTest(
fixture.TestSqlLoggerFactory.Clear();
}
+ public override void Changes_in_derived_related_entities_are_detected()
+ {
+ base.Changes_in_derived_related_entities_are_detected();
+
+ AssertSql(
+ @"SELECT [t].[Id], [t].[Name], [t].[BaseId], [t].[IsDerivedInheritanceRelationshipEntity], [t].[OwnedReferenceOnBase_Id], [t].[OwnedReferenceOnBase_Name], [t].[Id0], [t].[OwnedReferenceOnDerived_Id], [t].[OwnedReferenceOnDerived_Name], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [b0].[Name], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [d0].[Name], [t0].[Id], [t0].[BaseParentId], [t0].[Name], [t0].[DerivedProperty], [t0].[IsDerivedCollectionOnBase]
+FROM (
+ SELECT TOP(2) [b].[Id], [b].[Name], [d].[BaseId], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedInheritanceRelationshipEntity], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id] AS [Id0], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name]
+ FROM [BaseEntities] AS [b]
+ LEFT JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+ WHERE [b].[Name] = N'Derived1(4)'
+) AS [t]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b0] ON [t].[Id] = [b0].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d0] ON [t].[Id] = [d0].[DerivedInheritanceRelationshipEntityId]
+LEFT JOIN (
+ SELECT [b1].[Id], [b1].[BaseParentId], [b1].[Name], [d1].[DerivedProperty], CASE
+ WHEN [d1].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedCollectionOnBase]
+ FROM [BaseCollectionsOnBase] AS [b1]
+ LEFT JOIN [DerivedCollectionsOnBase] AS [d1] ON [b1].[Id] = [d1].[Id]
+) AS [t0] ON [t].[Id] = [t0].[BaseParentId]
+ORDER BY [t].[Id], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [t0].[Id]");
+ }
+
+ public override void Include_collection_without_inheritance()
+ {
+ base.Include_collection_without_inheritance();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [d].[BaseId], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsDerivedInheritanceRelationshipEntity], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [b0].[Name], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [d0].[Name], [c].[Id], [c].[Name], [c].[ParentId]
+FROM [BaseEntities] AS [b]
+LEFT JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b0] ON [b].[Id] = [b0].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d0] ON [b].[Id] = [d0].[DerivedInheritanceRelationshipEntityId]
+LEFT JOIN [CollectionsOnBase] AS [c] ON [b].[Id] = [c].[ParentId]
+ORDER BY [b].[Id], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [c].[Id]");
+ }
+
+ public override void Include_collection_without_inheritance_reverse()
+ {
+ base.Include_collection_without_inheritance_reverse();
+
+ AssertSql(
+ @"SELECT [c].[Id], [c].[Name], [c].[ParentId], [t].[Id], [t].[Name], [t].[BaseId], [t].[IsDerivedInheritanceRelationshipEntity], [t].[Id0], [t].[OwnedReferenceOnBase_Id], [t].[OwnedReferenceOnBase_Name], [t].[Id1], [t].[OwnedReferenceOnDerived_Id], [t].[OwnedReferenceOnDerived_Name], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [b0].[Name], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [d0].[Name]
+FROM [CollectionsOnBase] AS [c]
+LEFT JOIN (
+ SELECT [b].[Id], [b].[Name], [d].[BaseId], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedInheritanceRelationshipEntity], [b].[Id] AS [Id0], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id] AS [Id1], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name]
+ FROM [BaseEntities] AS [b]
+ LEFT JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+) AS [t] ON [c].[ParentId] = [t].[Id]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b0] ON [t].[Id] = [b0].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d0] ON [t].[Id] = [d0].[DerivedInheritanceRelationshipEntityId]
+ORDER BY [c].[Id], [t].[Id], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id]");
+ }
+
+ public override void Include_collection_without_inheritance_with_filter()
+ {
+ base.Include_collection_without_inheritance_with_filter();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [d].[BaseId], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsDerivedInheritanceRelationshipEntity], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [b0].[Name], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [d0].[Name], [c].[Id], [c].[Name], [c].[ParentId]
+FROM [BaseEntities] AS [b]
+LEFT JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b0] ON [b].[Id] = [b0].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d0] ON [b].[Id] = [d0].[DerivedInheritanceRelationshipEntityId]
+LEFT JOIN [CollectionsOnBase] AS [c] ON [b].[Id] = [c].[ParentId]
+WHERE ([b].[Name] <> N'Bar') OR [b].[Name] IS NULL
+ORDER BY [b].[Id], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [c].[Id]");
+ }
+
+ public override void Include_collection_without_inheritance_with_filter_reverse()
+ {
+ base.Include_collection_without_inheritance_with_filter_reverse();
+
+ AssertSql(
+ @"SELECT [c].[Id], [c].[Name], [c].[ParentId], [t].[Id], [t].[Name], [t].[BaseId], [t].[IsDerivedInheritanceRelationshipEntity], [t].[Id0], [t].[OwnedReferenceOnBase_Id], [t].[OwnedReferenceOnBase_Name], [t].[Id1], [t].[OwnedReferenceOnDerived_Id], [t].[OwnedReferenceOnDerived_Name], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [b0].[Name], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [d0].[Name]
+FROM [CollectionsOnBase] AS [c]
+LEFT JOIN (
+ SELECT [b].[Id], [b].[Name], [d].[BaseId], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedInheritanceRelationshipEntity], [b].[Id] AS [Id0], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id] AS [Id1], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name]
+ FROM [BaseEntities] AS [b]
+ LEFT JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+) AS [t] ON [c].[ParentId] = [t].[Id]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b0] ON [t].[Id] = [b0].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d0] ON [t].[Id] = [d0].[DerivedInheritanceRelationshipEntityId]
+WHERE ([c].[Name] <> N'Bar') OR [c].[Name] IS NULL
+ORDER BY [c].[Id], [t].[Id], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id]");
+ }
+
+ public override void Include_collection_with_inheritance()
+ {
+ base.Include_collection_with_inheritance();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [d].[BaseId], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsDerivedInheritanceRelationshipEntity], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [b0].[Name], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [d0].[Name], [t].[Id], [t].[BaseParentId], [t].[Name], [t].[DerivedProperty], [t].[IsDerivedCollectionOnBase]
+FROM [BaseEntities] AS [b]
+LEFT JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b0] ON [b].[Id] = [b0].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d0] ON [b].[Id] = [d0].[DerivedInheritanceRelationshipEntityId]
+LEFT JOIN (
+ SELECT [b1].[Id], [b1].[BaseParentId], [b1].[Name], [d1].[DerivedProperty], CASE
+ WHEN [d1].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedCollectionOnBase]
+ FROM [BaseCollectionsOnBase] AS [b1]
+ LEFT JOIN [DerivedCollectionsOnBase] AS [d1] ON [b1].[Id] = [d1].[Id]
+) AS [t] ON [b].[Id] = [t].[BaseParentId]
+ORDER BY [b].[Id], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [t].[Id]");
+ }
+
+ public override void Include_collection_with_inheritance_on_derived1()
+ {
+ base.Include_collection_with_inheritance_on_derived1();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [d].[BaseId], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [b0].[Name], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [d0].[Name], [t].[Id], [t].[BaseParentId], [t].[Name], [t].[DerivedProperty], [t].[IsDerivedCollectionOnBase]
+FROM [BaseEntities] AS [b]
+INNER JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b0] ON [b].[Id] = [b0].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d0] ON [b].[Id] = [d0].[DerivedInheritanceRelationshipEntityId]
+LEFT JOIN (
+ SELECT [b1].[Id], [b1].[BaseParentId], [b1].[Name], [d1].[DerivedProperty], CASE
+ WHEN [d1].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedCollectionOnBase]
+ FROM [BaseCollectionsOnBase] AS [b1]
+ LEFT JOIN [DerivedCollectionsOnBase] AS [d1] ON [b1].[Id] = [d1].[Id]
+) AS [t] ON [b].[Id] = [t].[BaseParentId]
+ORDER BY [b].[Id], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [t].[Id]");
+ }
+
+ public override void Include_collection_with_inheritance_on_derived2()
+ {
+ base.Include_collection_with_inheritance_on_derived2();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [d].[BaseId], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [b0].[Name], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [d0].[Name], [t].[Id], [t].[Name], [t].[ParentId], [t].[DerivedInheritanceRelationshipEntityId], [t].[IsDerivedCollectionOnDerived]
+FROM [BaseEntities] AS [b]
+INNER JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b0] ON [b].[Id] = [b0].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d0] ON [b].[Id] = [d0].[DerivedInheritanceRelationshipEntityId]
+LEFT JOIN (
+ SELECT [b1].[Id], [b1].[Name], [b1].[ParentId], [d1].[DerivedInheritanceRelationshipEntityId], CASE
+ WHEN [d1].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedCollectionOnDerived]
+ FROM [BaseCollectionsOnDerived] AS [b1]
+ LEFT JOIN [DerivedCollectionsOnDerived] AS [d1] ON [b1].[Id] = [d1].[Id]
+) AS [t] ON [b].[Id] = [t].[ParentId]
+ORDER BY [b].[Id], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [t].[Id]");
+ }
+
+ public override void Include_collection_with_inheritance_on_derived3()
+ {
+ base.Include_collection_with_inheritance_on_derived3();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [d].[BaseId], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [b0].[Name], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [d0].[Name], [t].[Id], [t].[Name], [t].[ParentId], [t].[DerivedInheritanceRelationshipEntityId]
+FROM [BaseEntities] AS [b]
+INNER JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b0] ON [b].[Id] = [b0].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d0] ON [b].[Id] = [d0].[DerivedInheritanceRelationshipEntityId]
+LEFT JOIN (
+ SELECT [b1].[Id], [b1].[Name], [b1].[ParentId], [d1].[DerivedInheritanceRelationshipEntityId]
+ FROM [BaseCollectionsOnDerived] AS [b1]
+ INNER JOIN [DerivedCollectionsOnDerived] AS [d1] ON [b1].[Id] = [d1].[Id]
+) AS [t] ON [b].[Id] = [t].[DerivedInheritanceRelationshipEntityId]
+ORDER BY [b].[Id], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [t].[Id]");
+ }
+
+ public override void Include_collection_with_inheritance_on_derived_reverse()
+ {
+ base.Include_collection_with_inheritance_on_derived_reverse();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [b].[ParentId], [d].[DerivedInheritanceRelationshipEntityId], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsDerivedCollectionOnDerived], [t].[Id], [t].[Name], [t].[BaseId], [t].[Id0], [t].[OwnedReferenceOnBase_Id], [t].[OwnedReferenceOnBase_Name], [t].[Id1], [t].[OwnedReferenceOnDerived_Id], [t].[OwnedReferenceOnDerived_Name], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [b1].[Name], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [d1].[Name]
+FROM [BaseCollectionsOnDerived] AS [b]
+LEFT JOIN [DerivedCollectionsOnDerived] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN (
+ SELECT [b0].[Id], [b0].[Name], [d0].[BaseId], [b0].[Id] AS [Id0], [b0].[OwnedReferenceOnBase_Id], [b0].[OwnedReferenceOnBase_Name], [d0].[Id] AS [Id1], [d0].[OwnedReferenceOnDerived_Id], [d0].[OwnedReferenceOnDerived_Name]
+ FROM [BaseEntities] AS [b0]
+ INNER JOIN [DerivedEntities] AS [d0] ON [b0].[Id] = [d0].[Id]
+) AS [t] ON [b].[ParentId] = [t].[Id]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b1] ON [t].[Id] = [b1].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d1] ON [t].[Id] = [d1].[DerivedInheritanceRelationshipEntityId]
+ORDER BY [b].[Id], [t].[Id], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id]");
+ }
+
+ public override void Include_collection_with_inheritance_reverse()
+ {
+ base.Include_collection_with_inheritance_reverse();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[BaseParentId], [b].[Name], [d].[DerivedProperty], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsDerivedCollectionOnBase], [t].[Id], [t].[Name], [t].[BaseId], [t].[IsDerivedInheritanceRelationshipEntity], [t].[Id0], [t].[OwnedReferenceOnBase_Id], [t].[OwnedReferenceOnBase_Name], [t].[Id1], [t].[OwnedReferenceOnDerived_Id], [t].[OwnedReferenceOnDerived_Name], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [b1].[Name], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [d1].[Name]
+FROM [BaseCollectionsOnBase] AS [b]
+LEFT JOIN [DerivedCollectionsOnBase] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN (
+ SELECT [b0].[Id], [b0].[Name], [d0].[BaseId], CASE
+ WHEN [d0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedInheritanceRelationshipEntity], [b0].[Id] AS [Id0], [b0].[OwnedReferenceOnBase_Id], [b0].[OwnedReferenceOnBase_Name], [d0].[Id] AS [Id1], [d0].[OwnedReferenceOnDerived_Id], [d0].[OwnedReferenceOnDerived_Name]
+ FROM [BaseEntities] AS [b0]
+ LEFT JOIN [DerivedEntities] AS [d0] ON [b0].[Id] = [d0].[Id]
+) AS [t] ON [b].[BaseParentId] = [t].[Id]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b1] ON [t].[Id] = [b1].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d1] ON [t].[Id] = [d1].[DerivedInheritanceRelationshipEntityId]
+ORDER BY [b].[Id], [t].[Id], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id]");
+ }
+
+ public override void Include_collection_with_inheritance_with_filter()
+ {
+ base.Include_collection_with_inheritance_with_filter();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [d].[BaseId], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsDerivedInheritanceRelationshipEntity], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [b0].[Name], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [d0].[Name], [t].[Id], [t].[BaseParentId], [t].[Name], [t].[DerivedProperty], [t].[IsDerivedCollectionOnBase]
+FROM [BaseEntities] AS [b]
+LEFT JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b0] ON [b].[Id] = [b0].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d0] ON [b].[Id] = [d0].[DerivedInheritanceRelationshipEntityId]
+LEFT JOIN (
+ SELECT [b1].[Id], [b1].[BaseParentId], [b1].[Name], [d1].[DerivedProperty], CASE
+ WHEN [d1].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedCollectionOnBase]
+ FROM [BaseCollectionsOnBase] AS [b1]
+ LEFT JOIN [DerivedCollectionsOnBase] AS [d1] ON [b1].[Id] = [d1].[Id]
+) AS [t] ON [b].[Id] = [t].[BaseParentId]
+WHERE ([b].[Name] <> N'Bar') OR [b].[Name] IS NULL
+ORDER BY [b].[Id], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [t].[Id]");
+ }
+
+ public override void Include_collection_with_inheritance_with_filter_reverse()
+ {
+ base.Include_collection_with_inheritance_with_filter_reverse();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[BaseParentId], [b].[Name], [d].[DerivedProperty], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsDerivedCollectionOnBase], [t].[Id], [t].[Name], [t].[BaseId], [t].[IsDerivedInheritanceRelationshipEntity], [t].[Id0], [t].[OwnedReferenceOnBase_Id], [t].[OwnedReferenceOnBase_Name], [t].[Id1], [t].[OwnedReferenceOnDerived_Id], [t].[OwnedReferenceOnDerived_Name], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [b1].[Name], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [d1].[Name]
+FROM [BaseCollectionsOnBase] AS [b]
+LEFT JOIN [DerivedCollectionsOnBase] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN (
+ SELECT [b0].[Id], [b0].[Name], [d0].[BaseId], CASE
+ WHEN [d0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedInheritanceRelationshipEntity], [b0].[Id] AS [Id0], [b0].[OwnedReferenceOnBase_Id], [b0].[OwnedReferenceOnBase_Name], [d0].[Id] AS [Id1], [d0].[OwnedReferenceOnDerived_Id], [d0].[OwnedReferenceOnDerived_Name]
+ FROM [BaseEntities] AS [b0]
+ LEFT JOIN [DerivedEntities] AS [d0] ON [b0].[Id] = [d0].[Id]
+) AS [t] ON [b].[BaseParentId] = [t].[Id]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b1] ON [t].[Id] = [b1].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d1] ON [t].[Id] = [d1].[DerivedInheritanceRelationshipEntityId]
+WHERE ([b].[Name] <> N'Bar') OR [b].[Name] IS NULL
+ORDER BY [b].[Id], [t].[Id], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id]");
+ }
+
+ public override void Include_reference_without_inheritance()
+ {
+ base.Include_reference_without_inheritance();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [d].[BaseId], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsDerivedInheritanceRelationshipEntity], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name], [r].[Id], [r].[Name], [r].[ParentId], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [b0].[Name], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [d0].[Name]
+FROM [BaseEntities] AS [b]
+LEFT JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN [ReferencesOnBase] AS [r] ON [b].[Id] = [r].[ParentId]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b0] ON [b].[Id] = [b0].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d0] ON [b].[Id] = [d0].[DerivedInheritanceRelationshipEntityId]
+ORDER BY [b].[Id], [r].[Id], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id]");
+ }
+
+ public override void Include_reference_without_inheritance_on_derived1()
+ {
+ base.Include_reference_without_inheritance_on_derived1();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [d].[BaseId], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name], [r].[Id], [r].[Name], [r].[ParentId], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [b0].[Name], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [d0].[Name]
+FROM [BaseEntities] AS [b]
+INNER JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN [ReferencesOnBase] AS [r] ON [b].[Id] = [r].[ParentId]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b0] ON [b].[Id] = [b0].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d0] ON [b].[Id] = [d0].[DerivedInheritanceRelationshipEntityId]
+ORDER BY [b].[Id], [r].[Id], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id]");
+ }
+
+ public override void Include_reference_without_inheritance_on_derived2()
+ {
+ base.Include_reference_without_inheritance_on_derived2();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [d].[BaseId], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name], [r].[Id], [r].[Name], [r].[ParentId], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [b0].[Name], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [d0].[Name]
+FROM [BaseEntities] AS [b]
+INNER JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN [ReferencesOnDerived] AS [r] ON [b].[Id] = [r].[ParentId]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b0] ON [b].[Id] = [b0].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d0] ON [b].[Id] = [d0].[DerivedInheritanceRelationshipEntityId]
+ORDER BY [b].[Id], [r].[Id], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id]");
+ }
+
+ public override void Include_reference_without_inheritance_on_derived_reverse()
+ {
+ base.Include_reference_without_inheritance_on_derived_reverse();
+
+ AssertSql(
+ @"SELECT [r].[Id], [r].[Name], [r].[ParentId], [t].[Id], [t].[Name], [t].[BaseId], [t].[Id0], [t].[OwnedReferenceOnBase_Id], [t].[OwnedReferenceOnBase_Name], [t].[Id1], [t].[OwnedReferenceOnDerived_Id], [t].[OwnedReferenceOnDerived_Name], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [b0].[Name], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [d0].[Name]
+FROM [ReferencesOnDerived] AS [r]
+LEFT JOIN (
+ SELECT [b].[Id], [b].[Name], [d].[BaseId], [b].[Id] AS [Id0], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id] AS [Id1], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name]
+ FROM [BaseEntities] AS [b]
+ INNER JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+) AS [t] ON [r].[ParentId] = [t].[Id]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b0] ON [t].[Id] = [b0].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d0] ON [t].[Id] = [d0].[DerivedInheritanceRelationshipEntityId]
+ORDER BY [r].[Id], [t].[Id], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id]");
+ }
+
+ public override void Include_reference_without_inheritance_reverse()
+ {
+ base.Include_reference_without_inheritance_reverse();
+
+ AssertSql(
+ @"SELECT [r].[Id], [r].[Name], [r].[ParentId], [t].[Id], [t].[Name], [t].[BaseId], [t].[IsDerivedInheritanceRelationshipEntity], [t].[Id0], [t].[OwnedReferenceOnBase_Id], [t].[OwnedReferenceOnBase_Name], [t].[Id1], [t].[OwnedReferenceOnDerived_Id], [t].[OwnedReferenceOnDerived_Name], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [b0].[Name], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [d0].[Name]
+FROM [ReferencesOnBase] AS [r]
+LEFT JOIN (
+ SELECT [b].[Id], [b].[Name], [d].[BaseId], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedInheritanceRelationshipEntity], [b].[Id] AS [Id0], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id] AS [Id1], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name]
+ FROM [BaseEntities] AS [b]
+ LEFT JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+) AS [t] ON [r].[ParentId] = [t].[Id]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b0] ON [t].[Id] = [b0].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d0] ON [t].[Id] = [d0].[DerivedInheritanceRelationshipEntityId]
+ORDER BY [r].[Id], [t].[Id], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id]");
+ }
+
+ public override void Include_reference_without_inheritance_with_filter()
+ {
+ base.Include_reference_without_inheritance_with_filter();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [d].[BaseId], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsDerivedInheritanceRelationshipEntity], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name], [r].[Id], [r].[Name], [r].[ParentId], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [b0].[Name], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [d0].[Name]
+FROM [BaseEntities] AS [b]
+LEFT JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN [ReferencesOnBase] AS [r] ON [b].[Id] = [r].[ParentId]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b0] ON [b].[Id] = [b0].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d0] ON [b].[Id] = [d0].[DerivedInheritanceRelationshipEntityId]
+WHERE ([b].[Name] <> N'Bar') OR [b].[Name] IS NULL
+ORDER BY [b].[Id], [r].[Id], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id]");
+ }
+
+ public override void Include_reference_without_inheritance_with_filter_reverse()
+ {
+ base.Include_reference_without_inheritance_with_filter_reverse();
+
+ AssertSql(
+ @"SELECT [r].[Id], [r].[Name], [r].[ParentId], [t].[Id], [t].[Name], [t].[BaseId], [t].[IsDerivedInheritanceRelationshipEntity], [t].[Id0], [t].[OwnedReferenceOnBase_Id], [t].[OwnedReferenceOnBase_Name], [t].[Id1], [t].[OwnedReferenceOnDerived_Id], [t].[OwnedReferenceOnDerived_Name], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [b0].[Name], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [d0].[Name]
+FROM [ReferencesOnBase] AS [r]
+LEFT JOIN (
+ SELECT [b].[Id], [b].[Name], [d].[BaseId], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedInheritanceRelationshipEntity], [b].[Id] AS [Id0], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id] AS [Id1], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name]
+ FROM [BaseEntities] AS [b]
+ LEFT JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+) AS [t] ON [r].[ParentId] = [t].[Id]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b0] ON [t].[Id] = [b0].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d0] ON [t].[Id] = [d0].[DerivedInheritanceRelationshipEntityId]
+WHERE ([r].[Name] <> N'Bar') OR [r].[Name] IS NULL
+ORDER BY [r].[Id], [t].[Id], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id]");
+ }
+
+ public override void Include_reference_with_inheritance()
+ {
+ base.Include_reference_with_inheritance();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [d].[BaseId], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsDerivedInheritanceRelationshipEntity], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name], [t].[Id], [t].[BaseParentId], [t].[Name], [t].[IsDerivedReferenceOnBase], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [b1].[Name], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [d1].[Name]
+FROM [BaseEntities] AS [b]
+LEFT JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN (
+ SELECT [b0].[Id], [b0].[BaseParentId], [b0].[Name], CASE
+ WHEN [d0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedReferenceOnBase]
+ FROM [BaseReferencesOnBase] AS [b0]
+ LEFT JOIN [DerivedReferencesOnBase] AS [d0] ON [b0].[Id] = [d0].[Id]
+) AS [t] ON [b].[Id] = [t].[BaseParentId]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b1] ON [b].[Id] = [b1].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d1] ON [b].[Id] = [d1].[DerivedInheritanceRelationshipEntityId]
+ORDER BY [b].[Id], [t].[Id], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id]");
+ }
+
+ public override void Include_reference_with_inheritance_on_derived1()
+ {
+ base.Include_reference_with_inheritance_on_derived1();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [d].[BaseId], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name], [t].[Id], [t].[BaseParentId], [t].[Name], [t].[IsDerivedReferenceOnBase], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [b1].[Name], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [d1].[Name]
+FROM [BaseEntities] AS [b]
+INNER JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN (
+ SELECT [b0].[Id], [b0].[BaseParentId], [b0].[Name], CASE
+ WHEN [d0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedReferenceOnBase]
+ FROM [BaseReferencesOnBase] AS [b0]
+ LEFT JOIN [DerivedReferencesOnBase] AS [d0] ON [b0].[Id] = [d0].[Id]
+) AS [t] ON [b].[Id] = [t].[BaseParentId]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b1] ON [b].[Id] = [b1].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d1] ON [b].[Id] = [d1].[DerivedInheritanceRelationshipEntityId]
+ORDER BY [b].[Id], [t].[Id], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id]");
+ }
+
+ public override void Include_reference_with_inheritance_on_derived2()
+ {
+ base.Include_reference_with_inheritance_on_derived2();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [d].[BaseId], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name], [t].[Id], [t].[BaseParentId], [t].[Name], [t].[DerivedInheritanceRelationshipEntityId], [t].[IsDerivedReferenceOnDerived], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [b1].[Name], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [d1].[Name]
+FROM [BaseEntities] AS [b]
+INNER JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN (
+ SELECT [b0].[Id], [b0].[BaseParentId], [b0].[Name], [d0].[DerivedInheritanceRelationshipEntityId], CASE
+ WHEN [d0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedReferenceOnDerived]
+ FROM [BaseReferencesOnDerived] AS [b0]
+ LEFT JOIN [DerivedReferencesOnDerived] AS [d0] ON [b0].[Id] = [d0].[Id]
+) AS [t] ON [b].[Id] = [t].[BaseParentId]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b1] ON [b].[Id] = [b1].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d1] ON [b].[Id] = [d1].[DerivedInheritanceRelationshipEntityId]
+ORDER BY [b].[Id], [t].[Id], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id]");
+ }
+
+ public override void Include_reference_with_inheritance_on_derived4()
+ {
+ base.Include_reference_with_inheritance_on_derived4();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [d].[BaseId], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name], [t].[Id], [t].[BaseParentId], [t].[Name], [t].[DerivedInheritanceRelationshipEntityId], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [b1].[Name], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [d1].[Name]
+FROM [BaseEntities] AS [b]
+INNER JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN (
+ SELECT [b0].[Id], [b0].[BaseParentId], [b0].[Name], [d0].[DerivedInheritanceRelationshipEntityId]
+ FROM [BaseReferencesOnDerived] AS [b0]
+ INNER JOIN [DerivedReferencesOnDerived] AS [d0] ON [b0].[Id] = [d0].[Id]
+) AS [t] ON [b].[Id] = [t].[DerivedInheritanceRelationshipEntityId]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b1] ON [b].[Id] = [b1].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d1] ON [b].[Id] = [d1].[DerivedInheritanceRelationshipEntityId]
+ORDER BY [b].[Id], [t].[Id], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id]");
+ }
+
+ public override void Include_reference_with_inheritance_on_derived_reverse()
+ {
+ base.Include_reference_with_inheritance_on_derived_reverse();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[BaseParentId], [b].[Name], [d].[DerivedInheritanceRelationshipEntityId], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsDerivedReferenceOnDerived], [t].[Id], [t].[Name], [t].[BaseId], [t].[Id0], [t].[OwnedReferenceOnBase_Id], [t].[OwnedReferenceOnBase_Name], [t].[Id1], [t].[OwnedReferenceOnDerived_Id], [t].[OwnedReferenceOnDerived_Name], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [b1].[Name], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [d1].[Name]
+FROM [BaseReferencesOnDerived] AS [b]
+LEFT JOIN [DerivedReferencesOnDerived] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN (
+ SELECT [b0].[Id], [b0].[Name], [d0].[BaseId], [b0].[Id] AS [Id0], [b0].[OwnedReferenceOnBase_Id], [b0].[OwnedReferenceOnBase_Name], [d0].[Id] AS [Id1], [d0].[OwnedReferenceOnDerived_Id], [d0].[OwnedReferenceOnDerived_Name]
+ FROM [BaseEntities] AS [b0]
+ INNER JOIN [DerivedEntities] AS [d0] ON [b0].[Id] = [d0].[Id]
+) AS [t] ON [b].[BaseParentId] = [t].[Id]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b1] ON [t].[Id] = [b1].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d1] ON [t].[Id] = [d1].[DerivedInheritanceRelationshipEntityId]
+ORDER BY [b].[Id], [t].[Id], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id]");
+ }
+
+ public override void Include_reference_with_inheritance_on_derived_with_filter1()
+ {
+ base.Include_reference_with_inheritance_on_derived_with_filter1();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [d].[BaseId], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name], [t].[Id], [t].[BaseParentId], [t].[Name], [t].[IsDerivedReferenceOnBase], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [b1].[Name], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [d1].[Name]
+FROM [BaseEntities] AS [b]
+INNER JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN (
+ SELECT [b0].[Id], [b0].[BaseParentId], [b0].[Name], CASE
+ WHEN [d0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedReferenceOnBase]
+ FROM [BaseReferencesOnBase] AS [b0]
+ LEFT JOIN [DerivedReferencesOnBase] AS [d0] ON [b0].[Id] = [d0].[Id]
+) AS [t] ON [b].[Id] = [t].[BaseParentId]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b1] ON [b].[Id] = [b1].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d1] ON [b].[Id] = [d1].[DerivedInheritanceRelationshipEntityId]
+WHERE ([b].[Name] <> N'Bar') OR [b].[Name] IS NULL
+ORDER BY [b].[Id], [t].[Id], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id]");
+ }
+
+ public override void Include_reference_with_inheritance_on_derived_with_filter2()
+ {
+ base.Include_reference_with_inheritance_on_derived_with_filter2();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [d].[BaseId], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name], [t].[Id], [t].[BaseParentId], [t].[Name], [t].[DerivedInheritanceRelationshipEntityId], [t].[IsDerivedReferenceOnDerived], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [b1].[Name], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [d1].[Name]
+FROM [BaseEntities] AS [b]
+INNER JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN (
+ SELECT [b0].[Id], [b0].[BaseParentId], [b0].[Name], [d0].[DerivedInheritanceRelationshipEntityId], CASE
+ WHEN [d0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedReferenceOnDerived]
+ FROM [BaseReferencesOnDerived] AS [b0]
+ LEFT JOIN [DerivedReferencesOnDerived] AS [d0] ON [b0].[Id] = [d0].[Id]
+) AS [t] ON [b].[Id] = [t].[BaseParentId]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b1] ON [b].[Id] = [b1].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d1] ON [b].[Id] = [d1].[DerivedInheritanceRelationshipEntityId]
+WHERE ([b].[Name] <> N'Bar') OR [b].[Name] IS NULL
+ORDER BY [b].[Id], [t].[Id], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id]");
+ }
+
+ public override void Include_reference_with_inheritance_on_derived_with_filter4()
+ {
+ base.Include_reference_with_inheritance_on_derived_with_filter4();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [d].[BaseId], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name], [t].[Id], [t].[BaseParentId], [t].[Name], [t].[DerivedInheritanceRelationshipEntityId], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [b1].[Name], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [d1].[Name]
+FROM [BaseEntities] AS [b]
+INNER JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN (
+ SELECT [b0].[Id], [b0].[BaseParentId], [b0].[Name], [d0].[DerivedInheritanceRelationshipEntityId]
+ FROM [BaseReferencesOnDerived] AS [b0]
+ INNER JOIN [DerivedReferencesOnDerived] AS [d0] ON [b0].[Id] = [d0].[Id]
+) AS [t] ON [b].[Id] = [t].[DerivedInheritanceRelationshipEntityId]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b1] ON [b].[Id] = [b1].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d1] ON [b].[Id] = [d1].[DerivedInheritanceRelationshipEntityId]
+WHERE ([b].[Name] <> N'Bar') OR [b].[Name] IS NULL
+ORDER BY [b].[Id], [t].[Id], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id]");
+ }
+
+ public override void Include_reference_with_inheritance_on_derived_with_filter_reverse()
+ {
+ base.Include_reference_with_inheritance_on_derived_with_filter_reverse();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[BaseParentId], [b].[Name], [d].[DerivedInheritanceRelationshipEntityId], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsDerivedReferenceOnDerived], [t].[Id], [t].[Name], [t].[BaseId], [t].[Id0], [t].[OwnedReferenceOnBase_Id], [t].[OwnedReferenceOnBase_Name], [t].[Id1], [t].[OwnedReferenceOnDerived_Id], [t].[OwnedReferenceOnDerived_Name], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [b1].[Name], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [d1].[Name]
+FROM [BaseReferencesOnDerived] AS [b]
+LEFT JOIN [DerivedReferencesOnDerived] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN (
+ SELECT [b0].[Id], [b0].[Name], [d0].[BaseId], [b0].[Id] AS [Id0], [b0].[OwnedReferenceOnBase_Id], [b0].[OwnedReferenceOnBase_Name], [d0].[Id] AS [Id1], [d0].[OwnedReferenceOnDerived_Id], [d0].[OwnedReferenceOnDerived_Name]
+ FROM [BaseEntities] AS [b0]
+ INNER JOIN [DerivedEntities] AS [d0] ON [b0].[Id] = [d0].[Id]
+) AS [t] ON [b].[BaseParentId] = [t].[Id]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b1] ON [t].[Id] = [b1].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d1] ON [t].[Id] = [d1].[DerivedInheritanceRelationshipEntityId]
+WHERE ([b].[Name] <> N'Bar') OR [b].[Name] IS NULL
+ORDER BY [b].[Id], [t].[Id], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id]");
+ }
+
+ public override void Include_reference_with_inheritance_reverse()
+ {
+ base.Include_reference_with_inheritance_reverse();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[BaseParentId], [b].[Name], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsDerivedReferenceOnBase], [t].[Id], [t].[Name], [t].[BaseId], [t].[IsDerivedInheritanceRelationshipEntity], [t].[Id0], [t].[OwnedReferenceOnBase_Id], [t].[OwnedReferenceOnBase_Name], [t].[Id1], [t].[OwnedReferenceOnDerived_Id], [t].[OwnedReferenceOnDerived_Name], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [b1].[Name], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [d1].[Name]
+FROM [BaseReferencesOnBase] AS [b]
+LEFT JOIN [DerivedReferencesOnBase] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN (
+ SELECT [b0].[Id], [b0].[Name], [d0].[BaseId], CASE
+ WHEN [d0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedInheritanceRelationshipEntity], [b0].[Id] AS [Id0], [b0].[OwnedReferenceOnBase_Id], [b0].[OwnedReferenceOnBase_Name], [d0].[Id] AS [Id1], [d0].[OwnedReferenceOnDerived_Id], [d0].[OwnedReferenceOnDerived_Name]
+ FROM [BaseEntities] AS [b0]
+ LEFT JOIN [DerivedEntities] AS [d0] ON [b0].[Id] = [d0].[Id]
+) AS [t] ON [b].[BaseParentId] = [t].[Id]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b1] ON [t].[Id] = [b1].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d1] ON [t].[Id] = [d1].[DerivedInheritanceRelationshipEntityId]
+ORDER BY [b].[Id], [t].[Id], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id]");
+ }
+
+ public override void Include_reference_with_inheritance_with_filter()
+ {
+ base.Include_reference_with_inheritance_with_filter();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [d].[BaseId], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsDerivedInheritanceRelationshipEntity], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name], [t].[Id], [t].[BaseParentId], [t].[Name], [t].[IsDerivedReferenceOnBase], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [b1].[Name], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [d1].[Name]
+FROM [BaseEntities] AS [b]
+LEFT JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN (
+ SELECT [b0].[Id], [b0].[BaseParentId], [b0].[Name], CASE
+ WHEN [d0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedReferenceOnBase]
+ FROM [BaseReferencesOnBase] AS [b0]
+ LEFT JOIN [DerivedReferencesOnBase] AS [d0] ON [b0].[Id] = [d0].[Id]
+) AS [t] ON [b].[Id] = [t].[BaseParentId]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b1] ON [b].[Id] = [b1].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d1] ON [b].[Id] = [d1].[DerivedInheritanceRelationshipEntityId]
+WHERE ([b].[Name] <> N'Bar') OR [b].[Name] IS NULL
+ORDER BY [b].[Id], [t].[Id], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id]");
+ }
+
+ public override void Include_reference_with_inheritance_with_filter_reverse()
+ {
+ base.Include_reference_with_inheritance_with_filter_reverse();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[BaseParentId], [b].[Name], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsDerivedReferenceOnBase], [t].[Id], [t].[Name], [t].[BaseId], [t].[IsDerivedInheritanceRelationshipEntity], [t].[Id0], [t].[OwnedReferenceOnBase_Id], [t].[OwnedReferenceOnBase_Name], [t].[Id1], [t].[OwnedReferenceOnDerived_Id], [t].[OwnedReferenceOnDerived_Name], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [b1].[Name], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [d1].[Name]
+FROM [BaseReferencesOnBase] AS [b]
+LEFT JOIN [DerivedReferencesOnBase] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN (
+ SELECT [b0].[Id], [b0].[Name], [d0].[BaseId], CASE
+ WHEN [d0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedInheritanceRelationshipEntity], [b0].[Id] AS [Id0], [b0].[OwnedReferenceOnBase_Id], [b0].[OwnedReferenceOnBase_Name], [d0].[Id] AS [Id1], [d0].[OwnedReferenceOnDerived_Id], [d0].[OwnedReferenceOnDerived_Name]
+ FROM [BaseEntities] AS [b0]
+ LEFT JOIN [DerivedEntities] AS [d0] ON [b0].[Id] = [d0].[Id]
+) AS [t] ON [b].[BaseParentId] = [t].[Id]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b1] ON [t].[Id] = [b1].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d1] ON [t].[Id] = [d1].[DerivedInheritanceRelationshipEntityId]
+WHERE ([b].[Name] <> N'Bar') OR [b].[Name] IS NULL
+ORDER BY [b].[Id], [t].[Id], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id]");
+ }
+
+ public override void Include_self_reference_with_inheritance()
+ {
+ base.Include_self_reference_with_inheritance();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [d].[BaseId], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsDerivedInheritanceRelationshipEntity], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name], [t].[Id], [t].[Name], [t].[BaseId], [t].[Id0], [t].[OwnedReferenceOnBase_Id], [t].[OwnedReferenceOnBase_Name], [t].[Id1], [t].[OwnedReferenceOnDerived_Id], [t].[OwnedReferenceOnDerived_Name], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [b1].[Name], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [d1].[Name], [b2].[BaseInheritanceRelationshipEntityId], [b2].[Id], [b2].[Name], [d2].[DerivedInheritanceRelationshipEntityId], [d2].[Id], [d2].[Name]
+FROM [BaseEntities] AS [b]
+LEFT JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN (
+ SELECT [b0].[Id], [b0].[Name], [d0].[BaseId], [b0].[Id] AS [Id0], [b0].[OwnedReferenceOnBase_Id], [b0].[OwnedReferenceOnBase_Name], [d0].[Id] AS [Id1], [d0].[OwnedReferenceOnDerived_Id], [d0].[OwnedReferenceOnDerived_Name]
+ FROM [BaseEntities] AS [b0]
+ INNER JOIN [DerivedEntities] AS [d0] ON [b0].[Id] = [d0].[Id]
+) AS [t] ON [b].[Id] = [t].[BaseId]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b1] ON [b].[Id] = [b1].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d1] ON [b].[Id] = [d1].[DerivedInheritanceRelationshipEntityId]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b2] ON [t].[Id] = [b2].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d2] ON [t].[Id] = [d2].[DerivedInheritanceRelationshipEntityId]
+ORDER BY [b].[Id], [t].[Id], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [b2].[BaseInheritanceRelationshipEntityId], [b2].[Id], [d2].[DerivedInheritanceRelationshipEntityId], [d2].[Id]");
+ }
+
+ public override void Include_self_reference_with_inheritance_reverse()
+ {
+ base.Include_self_reference_with_inheritance_reverse();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [d].[BaseId], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name], [t].[Id], [t].[Name], [t].[BaseId], [t].[IsDerivedInheritanceRelationshipEntity], [t].[Id0], [t].[OwnedReferenceOnBase_Id], [t].[OwnedReferenceOnBase_Name], [t].[Id1], [t].[OwnedReferenceOnDerived_Id], [t].[OwnedReferenceOnDerived_Name], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [b1].[Name], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [d1].[Name], [b2].[BaseInheritanceRelationshipEntityId], [b2].[Id], [b2].[Name], [d2].[DerivedInheritanceRelationshipEntityId], [d2].[Id], [d2].[Name]
+FROM [BaseEntities] AS [b]
+INNER JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN (
+ SELECT [b0].[Id], [b0].[Name], [d0].[BaseId], CASE
+ WHEN [d0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedInheritanceRelationshipEntity], [b0].[Id] AS [Id0], [b0].[OwnedReferenceOnBase_Id], [b0].[OwnedReferenceOnBase_Name], [d0].[Id] AS [Id1], [d0].[OwnedReferenceOnDerived_Id], [d0].[OwnedReferenceOnDerived_Name]
+ FROM [BaseEntities] AS [b0]
+ LEFT JOIN [DerivedEntities] AS [d0] ON [b0].[Id] = [d0].[Id]
+) AS [t] ON [d].[BaseId] = [t].[Id]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b1] ON [b].[Id] = [b1].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d1] ON [b].[Id] = [d1].[DerivedInheritanceRelationshipEntityId]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b2] ON [t].[Id] = [b2].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d2] ON [t].[Id] = [d2].[DerivedInheritanceRelationshipEntityId]
+ORDER BY [b].[Id], [t].[Id], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [b2].[BaseInheritanceRelationshipEntityId], [b2].[Id], [d2].[DerivedInheritanceRelationshipEntityId], [d2].[Id]");
+ }
+
+ public override void Nested_include_collection_reference_on_non_entity_base()
+ {
+ base.Nested_include_collection_reference_on_non_entity_base();
+
+ AssertSql(
+ @"SELECT [r].[Id], [r].[Name], [t].[Id], [t].[Name], [t].[ReferenceId], [t].[ReferencedEntityId], [t].[Id0], [t].[Name0]
+FROM [ReferencedEntities] AS [r]
+LEFT JOIN (
+ SELECT [p].[Id], [p].[Name], [p].[ReferenceId], [p].[ReferencedEntityId], [r0].[Id] AS [Id0], [r0].[Name] AS [Name0]
+ FROM [PrincipalEntities] AS [p]
+ LEFT JOIN [ReferencedEntities] AS [r0] ON [p].[ReferenceId] = [r0].[Id]
+) AS [t] ON [r].[Id] = [t].[ReferencedEntityId]
+ORDER BY [r].[Id], [t].[Id], [t].[Id0]");
+ }
+
+ public override void Nested_include_with_inheritance_collection_collection()
+ {
+ base.Nested_include_with_inheritance_collection_collection();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [d].[BaseId], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsDerivedInheritanceRelationshipEntity], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [b0].[Name], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [d0].[Name], [t0].[Id], [t0].[BaseParentId], [t0].[Name], [t0].[DerivedProperty], [t0].[IsDerivedCollectionOnBase], [t0].[Id0], [t0].[Name0], [t0].[ParentCollectionId], [t0].[ParentReferenceId], [t0].[IsNestedCollectionDerived]
+FROM [BaseEntities] AS [b]
+LEFT JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b0] ON [b].[Id] = [b0].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d0] ON [b].[Id] = [d0].[DerivedInheritanceRelationshipEntityId]
+LEFT JOIN (
+ SELECT [b1].[Id], [b1].[BaseParentId], [b1].[Name], [d1].[DerivedProperty], CASE
+ WHEN [d1].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedCollectionOnBase], [t].[Id] AS [Id0], [t].[Name] AS [Name0], [t].[ParentCollectionId], [t].[ParentReferenceId], [t].[IsNestedCollectionDerived]
+ FROM [BaseCollectionsOnBase] AS [b1]
+ LEFT JOIN [DerivedCollectionsOnBase] AS [d1] ON [b1].[Id] = [d1].[Id]
+ LEFT JOIN (
+ SELECT [n].[Id], [n].[Name], [n].[ParentCollectionId], [n].[ParentReferenceId], CASE
+ WHEN [n0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsNestedCollectionDerived]
+ FROM [NestedCollections] AS [n]
+ LEFT JOIN [NestedCollectionsDerived] AS [n0] ON [n].[Id] = [n0].[Id]
+ ) AS [t] ON [b1].[Id] = [t].[ParentCollectionId]
+) AS [t0] ON [b].[Id] = [t0].[BaseParentId]
+ORDER BY [b].[Id], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [t0].[Id], [t0].[Id0]");
+ }
+
+ public override void Nested_include_with_inheritance_collection_collection_reverse()
+ {
+ base.Nested_include_with_inheritance_collection_collection_reverse();
+
+ AssertSql(
+ @"SELECT [n].[Id], [n].[Name], [n].[ParentCollectionId], [n].[ParentReferenceId], CASE
+ WHEN [n0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsNestedCollectionDerived], [t].[Id], [t].[BaseParentId], [t].[Name], [t].[DerivedProperty], [t].[IsDerivedCollectionOnBase], [t0].[Id], [t0].[Name], [t0].[BaseId], [t0].[IsDerivedInheritanceRelationshipEntity], [t0].[Id0], [t0].[OwnedReferenceOnBase_Id], [t0].[OwnedReferenceOnBase_Name], [t0].[Id1], [t0].[OwnedReferenceOnDerived_Id], [t0].[OwnedReferenceOnDerived_Name], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [b1].[Name], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [d1].[Name]
+FROM [NestedCollections] AS [n]
+LEFT JOIN [NestedCollectionsDerived] AS [n0] ON [n].[Id] = [n0].[Id]
+LEFT JOIN (
+ SELECT [b].[Id], [b].[BaseParentId], [b].[Name], [d].[DerivedProperty], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedCollectionOnBase]
+ FROM [BaseCollectionsOnBase] AS [b]
+ LEFT JOIN [DerivedCollectionsOnBase] AS [d] ON [b].[Id] = [d].[Id]
+) AS [t] ON [n].[ParentCollectionId] = [t].[Id]
+LEFT JOIN (
+ SELECT [b0].[Id], [b0].[Name], [d0].[BaseId], CASE
+ WHEN [d0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedInheritanceRelationshipEntity], [b0].[Id] AS [Id0], [b0].[OwnedReferenceOnBase_Id], [b0].[OwnedReferenceOnBase_Name], [d0].[Id] AS [Id1], [d0].[OwnedReferenceOnDerived_Id], [d0].[OwnedReferenceOnDerived_Name]
+ FROM [BaseEntities] AS [b0]
+ LEFT JOIN [DerivedEntities] AS [d0] ON [b0].[Id] = [d0].[Id]
+) AS [t0] ON [t].[BaseParentId] = [t0].[Id]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b1] ON [t0].[Id] = [b1].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d1] ON [t0].[Id] = [d1].[DerivedInheritanceRelationshipEntityId]
+ORDER BY [n].[Id], [t].[Id], [t0].[Id], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id]");
+ }
+
+ public override void Nested_include_with_inheritance_collection_reference()
+ {
+ base.Nested_include_with_inheritance_collection_reference();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [d].[BaseId], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsDerivedInheritanceRelationshipEntity], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [b0].[Name], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [d0].[Name], [t0].[Id], [t0].[BaseParentId], [t0].[Name], [t0].[DerivedProperty], [t0].[IsDerivedCollectionOnBase], [t0].[Id0], [t0].[Name0], [t0].[ParentCollectionId], [t0].[ParentReferenceId], [t0].[IsNestedReferenceDerived]
+FROM [BaseEntities] AS [b]
+LEFT JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b0] ON [b].[Id] = [b0].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d0] ON [b].[Id] = [d0].[DerivedInheritanceRelationshipEntityId]
+LEFT JOIN (
+ SELECT [b1].[Id], [b1].[BaseParentId], [b1].[Name], [d1].[DerivedProperty], CASE
+ WHEN [d1].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedCollectionOnBase], [t].[Id] AS [Id0], [t].[Name] AS [Name0], [t].[ParentCollectionId], [t].[ParentReferenceId], [t].[IsNestedReferenceDerived]
+ FROM [BaseCollectionsOnBase] AS [b1]
+ LEFT JOIN [DerivedCollectionsOnBase] AS [d1] ON [b1].[Id] = [d1].[Id]
+ LEFT JOIN (
+ SELECT [n].[Id], [n].[Name], [n].[ParentCollectionId], [n].[ParentReferenceId], CASE
+ WHEN [n0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsNestedReferenceDerived]
+ FROM [NestedReferences] AS [n]
+ LEFT JOIN [NestedReferencesDerived] AS [n0] ON [n].[Id] = [n0].[Id]
+ ) AS [t] ON [b1].[Id] = [t].[ParentCollectionId]
+) AS [t0] ON [b].[Id] = [t0].[BaseParentId]
+ORDER BY [b].[Id], [b0].[BaseInheritanceRelationshipEntityId], [b0].[Id], [d0].[DerivedInheritanceRelationshipEntityId], [d0].[Id], [t0].[Id], [t0].[Id0]");
+ }
+
+ public override void Nested_include_with_inheritance_collection_reference_reverse()
+ {
+ base.Nested_include_with_inheritance_collection_reference_reverse();
+
+ AssertSql(
+ @"SELECT [n].[Id], [n].[Name], [n].[ParentCollectionId], [n].[ParentReferenceId], CASE
+ WHEN [n0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsNestedReferenceDerived], [t].[Id], [t].[BaseParentId], [t].[Name], [t].[DerivedProperty], [t].[IsDerivedCollectionOnBase], [t0].[Id], [t0].[Name], [t0].[BaseId], [t0].[IsDerivedInheritanceRelationshipEntity], [t0].[Id0], [t0].[OwnedReferenceOnBase_Id], [t0].[OwnedReferenceOnBase_Name], [t0].[Id1], [t0].[OwnedReferenceOnDerived_Id], [t0].[OwnedReferenceOnDerived_Name], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [b1].[Name], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [d1].[Name]
+FROM [NestedReferences] AS [n]
+LEFT JOIN [NestedReferencesDerived] AS [n0] ON [n].[Id] = [n0].[Id]
+LEFT JOIN (
+ SELECT [b].[Id], [b].[BaseParentId], [b].[Name], [d].[DerivedProperty], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedCollectionOnBase]
+ FROM [BaseCollectionsOnBase] AS [b]
+ LEFT JOIN [DerivedCollectionsOnBase] AS [d] ON [b].[Id] = [d].[Id]
+) AS [t] ON [n].[ParentCollectionId] = [t].[Id]
+LEFT JOIN (
+ SELECT [b0].[Id], [b0].[Name], [d0].[BaseId], CASE
+ WHEN [d0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedInheritanceRelationshipEntity], [b0].[Id] AS [Id0], [b0].[OwnedReferenceOnBase_Id], [b0].[OwnedReferenceOnBase_Name], [d0].[Id] AS [Id1], [d0].[OwnedReferenceOnDerived_Id], [d0].[OwnedReferenceOnDerived_Name]
+ FROM [BaseEntities] AS [b0]
+ LEFT JOIN [DerivedEntities] AS [d0] ON [b0].[Id] = [d0].[Id]
+) AS [t0] ON [t].[BaseParentId] = [t0].[Id]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b1] ON [t0].[Id] = [b1].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d1] ON [t0].[Id] = [d1].[DerivedInheritanceRelationshipEntityId]
+ORDER BY [n].[Id], [t].[Id], [t0].[Id], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id]");
+ }
+
+ public override void Nested_include_with_inheritance_reference_collection()
+ {
+ base.Nested_include_with_inheritance_reference_collection();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [d].[BaseId], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsDerivedInheritanceRelationshipEntity], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name], [t].[Id], [t].[BaseParentId], [t].[Name], [t].[IsDerivedReferenceOnBase], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [b1].[Name], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [d1].[Name], [t0].[Id], [t0].[Name], [t0].[ParentCollectionId], [t0].[ParentReferenceId], [t0].[IsNestedCollectionDerived]
+FROM [BaseEntities] AS [b]
+LEFT JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN (
+ SELECT [b0].[Id], [b0].[BaseParentId], [b0].[Name], CASE
+ WHEN [d0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedReferenceOnBase]
+ FROM [BaseReferencesOnBase] AS [b0]
+ LEFT JOIN [DerivedReferencesOnBase] AS [d0] ON [b0].[Id] = [d0].[Id]
+) AS [t] ON [b].[Id] = [t].[BaseParentId]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b1] ON [b].[Id] = [b1].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d1] ON [b].[Id] = [d1].[DerivedInheritanceRelationshipEntityId]
+LEFT JOIN (
+ SELECT [n].[Id], [n].[Name], [n].[ParentCollectionId], [n].[ParentReferenceId], CASE
+ WHEN [n0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsNestedCollectionDerived]
+ FROM [NestedCollections] AS [n]
+ LEFT JOIN [NestedCollectionsDerived] AS [n0] ON [n].[Id] = [n0].[Id]
+) AS [t0] ON [t].[Id] = [t0].[ParentReferenceId]
+ORDER BY [b].[Id], [t].[Id], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [t0].[Id]");
+ }
+
+ public override void Nested_include_with_inheritance_reference_collection_on_base()
+ {
+ base.Nested_include_with_inheritance_reference_collection_on_base();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [d].[BaseId], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name], [t].[Id], [t].[BaseParentId], [t].[Name], [t].[IsDerivedReferenceOnBase], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [b1].[Name], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [d1].[Name], [t0].[Id], [t0].[Name], [t0].[ParentCollectionId], [t0].[ParentReferenceId], [t0].[IsNestedCollectionDerived]
+FROM [BaseEntities] AS [b]
+INNER JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN (
+ SELECT [b0].[Id], [b0].[BaseParentId], [b0].[Name], CASE
+ WHEN [d0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedReferenceOnBase]
+ FROM [BaseReferencesOnBase] AS [b0]
+ LEFT JOIN [DerivedReferencesOnBase] AS [d0] ON [b0].[Id] = [d0].[Id]
+) AS [t] ON [b].[Id] = [t].[BaseParentId]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b1] ON [b].[Id] = [b1].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d1] ON [b].[Id] = [d1].[DerivedInheritanceRelationshipEntityId]
+LEFT JOIN (
+ SELECT [n].[Id], [n].[Name], [n].[ParentCollectionId], [n].[ParentReferenceId], CASE
+ WHEN [n0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsNestedCollectionDerived]
+ FROM [NestedCollections] AS [n]
+ LEFT JOIN [NestedCollectionsDerived] AS [n0] ON [n].[Id] = [n0].[Id]
+) AS [t0] ON [t].[Id] = [t0].[ParentReferenceId]
+ORDER BY [b].[Id], [t].[Id], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [t0].[Id]");
+ }
+
+ public override void Nested_include_with_inheritance_reference_collection_reverse()
+ {
+ base.Nested_include_with_inheritance_reference_collection_reverse();
+
+ AssertSql(
+ @"SELECT [n].[Id], [n].[Name], [n].[ParentCollectionId], [n].[ParentReferenceId], CASE
+ WHEN [n0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsNestedCollectionDerived], [t].[Id], [t].[BaseParentId], [t].[Name], [t].[IsDerivedReferenceOnBase], [t0].[Id], [t0].[Name], [t0].[BaseId], [t0].[IsDerivedInheritanceRelationshipEntity], [t0].[Id0], [t0].[OwnedReferenceOnBase_Id], [t0].[OwnedReferenceOnBase_Name], [t0].[Id1], [t0].[OwnedReferenceOnDerived_Id], [t0].[OwnedReferenceOnDerived_Name], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [b1].[Name], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [d1].[Name]
+FROM [NestedCollections] AS [n]
+LEFT JOIN [NestedCollectionsDerived] AS [n0] ON [n].[Id] = [n0].[Id]
+LEFT JOIN (
+ SELECT [b].[Id], [b].[BaseParentId], [b].[Name], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedReferenceOnBase]
+ FROM [BaseReferencesOnBase] AS [b]
+ LEFT JOIN [DerivedReferencesOnBase] AS [d] ON [b].[Id] = [d].[Id]
+) AS [t] ON [n].[ParentReferenceId] = [t].[Id]
+LEFT JOIN (
+ SELECT [b0].[Id], [b0].[Name], [d0].[BaseId], CASE
+ WHEN [d0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedInheritanceRelationshipEntity], [b0].[Id] AS [Id0], [b0].[OwnedReferenceOnBase_Id], [b0].[OwnedReferenceOnBase_Name], [d0].[Id] AS [Id1], [d0].[OwnedReferenceOnDerived_Id], [d0].[OwnedReferenceOnDerived_Name]
+ FROM [BaseEntities] AS [b0]
+ LEFT JOIN [DerivedEntities] AS [d0] ON [b0].[Id] = [d0].[Id]
+) AS [t0] ON [t].[BaseParentId] = [t0].[Id]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b1] ON [t0].[Id] = [b1].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d1] ON [t0].[Id] = [d1].[DerivedInheritanceRelationshipEntityId]
+ORDER BY [n].[Id], [t].[Id], [t0].[Id], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id]");
+ }
+
+ public override void Nested_include_with_inheritance_reference_reference()
+ {
+ base.Nested_include_with_inheritance_reference_reference();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [d].[BaseId], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsDerivedInheritanceRelationshipEntity], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name], [t].[Id], [t].[BaseParentId], [t].[Name], [t].[IsDerivedReferenceOnBase], [t0].[Id], [t0].[Name], [t0].[ParentCollectionId], [t0].[ParentReferenceId], [t0].[IsNestedReferenceDerived], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [b1].[Name], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [d1].[Name]
+FROM [BaseEntities] AS [b]
+LEFT JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN (
+ SELECT [b0].[Id], [b0].[BaseParentId], [b0].[Name], CASE
+ WHEN [d0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedReferenceOnBase]
+ FROM [BaseReferencesOnBase] AS [b0]
+ LEFT JOIN [DerivedReferencesOnBase] AS [d0] ON [b0].[Id] = [d0].[Id]
+) AS [t] ON [b].[Id] = [t].[BaseParentId]
+LEFT JOIN (
+ SELECT [n].[Id], [n].[Name], [n].[ParentCollectionId], [n].[ParentReferenceId], CASE
+ WHEN [n0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsNestedReferenceDerived]
+ FROM [NestedReferences] AS [n]
+ LEFT JOIN [NestedReferencesDerived] AS [n0] ON [n].[Id] = [n0].[Id]
+) AS [t0] ON [t].[Id] = [t0].[ParentReferenceId]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b1] ON [b].[Id] = [b1].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d1] ON [b].[Id] = [d1].[DerivedInheritanceRelationshipEntityId]
+ORDER BY [b].[Id], [t].[Id], [t0].[Id], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id]");
+ }
+
+ public override void Nested_include_with_inheritance_reference_reference_on_base()
+ {
+ base.Nested_include_with_inheritance_reference_reference_on_base();
+
+ AssertSql(
+ @"SELECT [b].[Id], [b].[Name], [d].[BaseId], [b].[OwnedReferenceOnBase_Id], [b].[OwnedReferenceOnBase_Name], [d].[Id], [d].[OwnedReferenceOnDerived_Id], [d].[OwnedReferenceOnDerived_Name], [t].[Id], [t].[BaseParentId], [t].[Name], [t].[IsDerivedReferenceOnBase], [t0].[Id], [t0].[Name], [t0].[ParentCollectionId], [t0].[ParentReferenceId], [t0].[IsNestedReferenceDerived], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [b1].[Name], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [d1].[Name]
+FROM [BaseEntities] AS [b]
+INNER JOIN [DerivedEntities] AS [d] ON [b].[Id] = [d].[Id]
+LEFT JOIN (
+ SELECT [b0].[Id], [b0].[BaseParentId], [b0].[Name], CASE
+ WHEN [d0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedReferenceOnBase]
+ FROM [BaseReferencesOnBase] AS [b0]
+ LEFT JOIN [DerivedReferencesOnBase] AS [d0] ON [b0].[Id] = [d0].[Id]
+) AS [t] ON [b].[Id] = [t].[BaseParentId]
+LEFT JOIN (
+ SELECT [n].[Id], [n].[Name], [n].[ParentCollectionId], [n].[ParentReferenceId], CASE
+ WHEN [n0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsNestedReferenceDerived]
+ FROM [NestedReferences] AS [n]
+ LEFT JOIN [NestedReferencesDerived] AS [n0] ON [n].[Id] = [n0].[Id]
+) AS [t0] ON [t].[Id] = [t0].[ParentReferenceId]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b1] ON [b].[Id] = [b1].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d1] ON [b].[Id] = [d1].[DerivedInheritanceRelationshipEntityId]
+ORDER BY [b].[Id], [t].[Id], [t0].[Id], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id]");
+ }
+
+ public override void Nested_include_with_inheritance_reference_reference_reverse()
+ {
+ base.Nested_include_with_inheritance_reference_reference_reverse();
+
+ AssertSql(
+ @"SELECT [n].[Id], [n].[Name], [n].[ParentCollectionId], [n].[ParentReferenceId], CASE
+ WHEN [n0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsNestedReferenceDerived], [t].[Id], [t].[BaseParentId], [t].[Name], [t].[IsDerivedReferenceOnBase], [t0].[Id], [t0].[Name], [t0].[BaseId], [t0].[IsDerivedInheritanceRelationshipEntity], [t0].[Id0], [t0].[OwnedReferenceOnBase_Id], [t0].[OwnedReferenceOnBase_Name], [t0].[Id1], [t0].[OwnedReferenceOnDerived_Id], [t0].[OwnedReferenceOnDerived_Name], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [b1].[Name], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id], [d1].[Name]
+FROM [NestedReferences] AS [n]
+LEFT JOIN [NestedReferencesDerived] AS [n0] ON [n].[Id] = [n0].[Id]
+LEFT JOIN (
+ SELECT [b].[Id], [b].[BaseParentId], [b].[Name], CASE
+ WHEN [d].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedReferenceOnBase]
+ FROM [BaseReferencesOnBase] AS [b]
+ LEFT JOIN [DerivedReferencesOnBase] AS [d] ON [b].[Id] = [d].[Id]
+) AS [t] ON [n].[ParentReferenceId] = [t].[Id]
+LEFT JOIN (
+ SELECT [b0].[Id], [b0].[Name], [d0].[BaseId], CASE
+ WHEN [d0].[Id] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsDerivedInheritanceRelationshipEntity], [b0].[Id] AS [Id0], [b0].[OwnedReferenceOnBase_Id], [b0].[OwnedReferenceOnBase_Name], [d0].[Id] AS [Id1], [d0].[OwnedReferenceOnDerived_Id], [d0].[OwnedReferenceOnDerived_Name]
+ FROM [BaseEntities] AS [b0]
+ LEFT JOIN [DerivedEntities] AS [d0] ON [b0].[Id] = [d0].[Id]
+) AS [t0] ON [t].[BaseParentId] = [t0].[Id]
+LEFT JOIN [BaseEntities_OwnedCollectionOnBase] AS [b1] ON [t0].[Id] = [b1].[BaseInheritanceRelationshipEntityId]
+LEFT JOIN [DerivedEntities_OwnedCollectionOnDerived] AS [d1] ON [t0].[Id] = [d1].[DerivedInheritanceRelationshipEntityId]
+ORDER BY [n].[Id], [t].[Id], [t0].[Id], [b1].[BaseInheritanceRelationshipEntityId], [b1].[Id], [d1].[DerivedInheritanceRelationshipEntityId], [d1].[Id]");
+ }
+
private void AssertSql(params string[] expected)
=> Fixture.TestSqlLoggerFactory.AssertBaseline(expected);
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/UdfDbFunctionSqlServerTests.cs b/test/EFCore.SqlServer.FunctionalTests/Query/UdfDbFunctionSqlServerTests.cs
index c3cf4752b2a..44601b32cf4 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/UdfDbFunctionSqlServerTests.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/UdfDbFunctionSqlServerTests.cs
@@ -1,4 +1,4 @@
-// Copyright (c) .NET Foundation. All rights reserved.
+// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.EntityFrameworkCore.TestUtilities;
@@ -742,10 +742,11 @@ public override void QF_Correlated_Func_Call_With_Navigation()
{
base.QF_Correlated_Func_Call_With_Navigation();
- AssertSql(@"SELECT [c].[Id], [t].[LastName], [t].[OrderId], [t].[Id]
+ AssertSql(
+ @"SELECT [c].[Id], [t].[CustomerName], [t].[OrderId], [t].[Id]
FROM [Customers] AS [c]
OUTER APPLY (
- SELECT [c0].[LastName], [m].[OrderId], [c0].[Id]
+ SELECT [c0].[LastName] AS [CustomerName], [m].[OrderId], [c0].[Id]
FROM [dbo].[GetOrdersWithMultipleProducts]([c].[Id]) AS [m]
INNER JOIN [Customers] AS [c0] ON [m].[CustomerId] = [c0].[Id]
) AS [t]
diff --git a/test/EFCore.SqlServer.FunctionalTests/TPTTableSplittingSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/TPTTableSplittingSqlServerTest.cs
new file mode 100644
index 00000000000..9043935dff4
--- /dev/null
+++ b/test/EFCore.SqlServer.FunctionalTests/TPTTableSplittingSqlServerTest.cs
@@ -0,0 +1,293 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Microsoft.EntityFrameworkCore.TestUtilities;
+using Xunit.Abstractions;
+
+namespace Microsoft.EntityFrameworkCore
+{
+ public class TPTTableSplittingSqlServerTest : TPTTableSplittingTestBase
+ {
+ public TPTTableSplittingSqlServerTest(ITestOutputHelper testOutputHelper)
+ : base(testOutputHelper)
+ {
+ }
+
+ protected override ITestStoreFactory TestStoreFactory => SqlServerTestStoreFactory.Instance;
+
+ public override void Can_use_with_redundant_relationships()
+ {
+ base.Can_use_with_redundant_relationships();
+
+ AssertSql(
+ @"SELECT [v].[Name], [v].[SeatingCapacity], CASE
+ WHEN [p].[Name] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsPoweredVehicle], [t0].[Name], [t0].[Operator_Name], [t0].[RequiredInt], [t0].[LicenseType], [t0].[IsLicensedOperator], [t3].[Name], [t3].[Type], [t5].[Name], [t5].[Description], [t5].[IsContinuousCombustionEngine], [t5].[IsIntermittentCombustionEngine], [t5].[IsSolidRocket], [t7].[VehicleName], [t7].[Capacity], [t7].[FuelType], [t7].[GrainGeometry], [t7].[IsSolidFuelTank]
+FROM [Vehicles] AS [v]
+LEFT JOIN [PoweredVehicles] AS [p] ON [v].[Name] = [p].[Name]
+LEFT JOIN (
+ SELECT [v0].[Name], [v0].[Operator_Name], [v0].[RequiredInt], [l].[LicenseType], CASE
+ WHEN [l].[VehicleName] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsLicensedOperator], [t].[Name] AS [Name0]
+ FROM [Vehicles] AS [v0]
+ LEFT JOIN [LicensedOperators] AS [l] ON [v0].[Name] = [l].[VehicleName]
+ INNER JOIN (
+ SELECT [v1].[Name], [v1].[SeatingCapacity], CASE
+ WHEN [p0].[Name] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsPoweredVehicle]
+ FROM [Vehicles] AS [v1]
+ LEFT JOIN [PoweredVehicles] AS [p0] ON [v1].[Name] = [p0].[Name]
+ ) AS [t] ON [v0].[Name] = [t].[Name]
+ WHERE [v0].[RequiredInt] IS NOT NULL
+) AS [t0] ON [v].[Name] = [t0].[Name]
+LEFT JOIN (
+ SELECT [v2].[Name], [v2].[Type], [t2].[Name] AS [Name0], [t2].[Name0] AS [Name00]
+ FROM [Vehicles] AS [v2]
+ INNER JOIN (
+ SELECT [v3].[Name], [v3].[Operator_Name], [v3].[RequiredInt], [l0].[LicenseType], CASE
+ WHEN [l0].[VehicleName] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsLicensedOperator], [t1].[Name] AS [Name0]
+ FROM [Vehicles] AS [v3]
+ LEFT JOIN [LicensedOperators] AS [l0] ON [v3].[Name] = [l0].[VehicleName]
+ INNER JOIN (
+ SELECT [v4].[Name], [v4].[SeatingCapacity], CASE
+ WHEN [p1].[Name] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsPoweredVehicle]
+ FROM [Vehicles] AS [v4]
+ LEFT JOIN [PoweredVehicles] AS [p1] ON [v4].[Name] = [p1].[Name]
+ ) AS [t1] ON [v3].[Name] = [t1].[Name]
+ WHERE [v3].[RequiredInt] IS NOT NULL
+ ) AS [t2] ON [v2].[Name] = [t2].[Name]
+ WHERE [v2].[Type] IS NOT NULL
+) AS [t3] ON [t0].[Name] = [t3].[Name]
+LEFT JOIN (
+ SELECT [p2].[Name], [p2].[Description], CASE
+ WHEN [c0].[VehicleName] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsContinuousCombustionEngine], CASE
+ WHEN [i].[VehicleName] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsIntermittentCombustionEngine], CASE
+ WHEN [s].[VehicleName] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsSolidRocket], [t4].[Name] AS [Name0]
+ FROM [PoweredVehicles] AS [p2]
+ LEFT JOIN [CombustionEngines] AS [c] ON [p2].[Name] = [c].[VehicleName]
+ LEFT JOIN [ContinuousCombustionEngines] AS [c0] ON [p2].[Name] = [c0].[VehicleName]
+ LEFT JOIN [IntermittentCombustionEngines] AS [i] ON [p2].[Name] = [i].[VehicleName]
+ LEFT JOIN [SolidRockets] AS [s] ON [p2].[Name] = [s].[VehicleName]
+ INNER JOIN (
+ SELECT [v5].[Name], [v5].[SeatingCapacity]
+ FROM [Vehicles] AS [v5]
+ INNER JOIN [PoweredVehicles] AS [p3] ON [v5].[Name] = [p3].[Name]
+ ) AS [t4] ON [p2].[Name] = [t4].[Name]
+ WHERE [p2].[Description] IS NOT NULL
+) AS [t5] ON [v].[Name] = [t5].[Name]
+LEFT JOIN (
+ SELECT [c1].[VehicleName], [c1].[Capacity], [c1].[FuelType], [s0].[GrainGeometry], CASE
+ WHEN [s0].[VehicleName] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsSolidFuelTank], [t6].[Name]
+ FROM [CombustionEngines] AS [c1]
+ LEFT JOIN [SolidFuelTanks] AS [s0] ON [c1].[VehicleName] = [s0].[VehicleName]
+ INNER JOIN (
+ SELECT [p4].[Name], [p4].[Description], CASE
+ WHEN [c3].[VehicleName] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsContinuousCombustionEngine], CASE
+ WHEN [i0].[VehicleName] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsIntermittentCombustionEngine], CASE
+ WHEN [s1].[VehicleName] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsSolidRocket]
+ FROM [PoweredVehicles] AS [p4]
+ INNER JOIN [CombustionEngines] AS [c2] ON [p4].[Name] = [c2].[VehicleName]
+ LEFT JOIN [ContinuousCombustionEngines] AS [c3] ON [p4].[Name] = [c3].[VehicleName]
+ LEFT JOIN [IntermittentCombustionEngines] AS [i0] ON [p4].[Name] = [i0].[VehicleName]
+ LEFT JOIN [SolidRockets] AS [s1] ON [p4].[Name] = [s1].[VehicleName]
+ ) AS [t6] ON [c1].[VehicleName] = [t6].[Name]
+ WHERE [c1].[FuelType] IS NOT NULL OR [c1].[Capacity] IS NOT NULL
+) AS [t7] ON [t5].[Name] = [t7].[VehicleName]
+ORDER BY [v].[Name]");
+ }
+
+ public override void Can_query_shared()
+ {
+ base.Can_query_shared();
+
+ AssertSql(
+ @"SELECT [v].[Name], [v].[Operator_Name], [v].[RequiredInt], [l].[LicenseType], CASE
+ WHEN [l].[VehicleName] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsLicensedOperator]
+FROM [Vehicles] AS [v]
+LEFT JOIN [LicensedOperators] AS [l] ON [v].[Name] = [l].[VehicleName]
+INNER JOIN (
+ SELECT [v0].[Name], [v0].[SeatingCapacity], CASE
+ WHEN [p].[Name] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsPoweredVehicle]
+ FROM [Vehicles] AS [v0]
+ LEFT JOIN [PoweredVehicles] AS [p] ON [v0].[Name] = [p].[Name]
+) AS [t] ON [v].[Name] = [t].[Name]
+WHERE [v].[RequiredInt] IS NOT NULL");
+ }
+
+ public override void Can_query_shared_nonhierarchy()
+ {
+ base.Can_query_shared_nonhierarchy();
+
+ AssertSql(
+ @"SELECT [v].[Name], [v].[Operator_Name], [v].[RequiredInt]
+FROM [Vehicles] AS [v]
+INNER JOIN (
+ SELECT [v0].[Name], [v0].[SeatingCapacity], CASE
+ WHEN [p].[Name] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsPoweredVehicle]
+ FROM [Vehicles] AS [v0]
+ LEFT JOIN [PoweredVehicles] AS [p] ON [v0].[Name] = [p].[Name]
+) AS [t] ON [v].[Name] = [t].[Name]
+WHERE [v].[RequiredInt] IS NOT NULL");
+ }
+
+ public override void Can_query_shared_nonhierarchy_with_nonshared_dependent()
+ {
+ base.Can_query_shared_nonhierarchy_with_nonshared_dependent();
+
+ AssertSql(
+ @"SELECT [v].[Name], [v].[Operator_Name], [v].[RequiredInt]
+FROM [Vehicles] AS [v]
+INNER JOIN (
+ SELECT [v0].[Name], [v0].[SeatingCapacity], CASE
+ WHEN [p].[Name] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsPoweredVehicle]
+ FROM [Vehicles] AS [v0]
+ LEFT JOIN [PoweredVehicles] AS [p] ON [v0].[Name] = [p].[Name]
+) AS [t] ON [v].[Name] = [t].[Name]
+WHERE [v].[RequiredInt] IS NOT NULL");
+ }
+
+ public override void Can_query_shared_derived_hierarchy()
+ {
+ base.Can_query_shared_derived_hierarchy();
+
+ AssertSql(
+ @"SELECT [c].[VehicleName], [c].[Capacity], [c].[FuelType], [s].[GrainGeometry], CASE
+ WHEN [s].[VehicleName] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+END AS [IsSolidFuelTank]
+FROM [CombustionEngines] AS [c]
+LEFT JOIN [SolidFuelTanks] AS [s] ON [c].[VehicleName] = [s].[VehicleName]
+INNER JOIN (
+ SELECT [p].[Name], [p].[Description], CASE
+ WHEN [c1].[VehicleName] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsContinuousCombustionEngine], CASE
+ WHEN [i].[VehicleName] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsIntermittentCombustionEngine], CASE
+ WHEN [s0].[VehicleName] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsSolidRocket]
+ FROM [PoweredVehicles] AS [p]
+ INNER JOIN [CombustionEngines] AS [c0] ON [p].[Name] = [c0].[VehicleName]
+ LEFT JOIN [ContinuousCombustionEngines] AS [c1] ON [p].[Name] = [c1].[VehicleName]
+ LEFT JOIN [IntermittentCombustionEngines] AS [i] ON [p].[Name] = [i].[VehicleName]
+ LEFT JOIN [SolidRockets] AS [s0] ON [p].[Name] = [s0].[VehicleName]
+) AS [t] ON [c].[VehicleName] = [t].[Name]
+WHERE [c].[FuelType] IS NOT NULL OR [c].[Capacity] IS NOT NULL");
+ }
+
+ public override void Can_query_shared_derived_nonhierarchy()
+ {
+ base.Can_query_shared_derived_nonhierarchy();
+
+ AssertSql(
+ @"SELECT [c].[VehicleName], [c].[Capacity], [c].[FuelType]
+FROM [CombustionEngines] AS [c]
+INNER JOIN (
+ SELECT [p].[Name], [p].[Description], CASE
+ WHEN [c1].[VehicleName] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsContinuousCombustionEngine], CASE
+ WHEN [i].[VehicleName] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsIntermittentCombustionEngine], CASE
+ WHEN [s].[VehicleName] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsSolidRocket]
+ FROM [PoweredVehicles] AS [p]
+ INNER JOIN [CombustionEngines] AS [c0] ON [p].[Name] = [c0].[VehicleName]
+ LEFT JOIN [ContinuousCombustionEngines] AS [c1] ON [p].[Name] = [c1].[VehicleName]
+ LEFT JOIN [IntermittentCombustionEngines] AS [i] ON [p].[Name] = [i].[VehicleName]
+ LEFT JOIN [SolidRockets] AS [s] ON [p].[Name] = [s].[VehicleName]
+) AS [t] ON [c].[VehicleName] = [t].[Name]
+WHERE [c].[FuelType] IS NOT NULL OR [c].[Capacity] IS NOT NULL");
+ }
+
+ public override void Can_query_shared_derived_nonhierarchy_all_required()
+ {
+ base.Can_query_shared_derived_nonhierarchy_all_required();
+
+ AssertSql(
+ @"SELECT [c].[VehicleName], [c].[Capacity], [c].[FuelType]
+FROM [CombustionEngines] AS [c]
+INNER JOIN (
+ SELECT [p].[Name], [p].[Description], CASE
+ WHEN [c1].[VehicleName] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsContinuousCombustionEngine], CASE
+ WHEN [i].[VehicleName] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsIntermittentCombustionEngine], CASE
+ WHEN [s].[VehicleName] IS NOT NULL THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS [IsSolidRocket]
+ FROM [PoweredVehicles] AS [p]
+ INNER JOIN [CombustionEngines] AS [c0] ON [p].[Name] = [c0].[VehicleName]
+ LEFT JOIN [ContinuousCombustionEngines] AS [c1] ON [p].[Name] = [c1].[VehicleName]
+ LEFT JOIN [IntermittentCombustionEngines] AS [i] ON [p].[Name] = [i].[VehicleName]
+ LEFT JOIN [SolidRockets] AS [s] ON [p].[Name] = [s].[VehicleName]
+) AS [t] ON [c].[VehicleName] = [t].[Name]
+WHERE [c].[FuelType] IS NOT NULL AND [c].[Capacity] IS NOT NULL");
+ }
+
+ public override void Can_change_dependent_instance_non_derived()
+ {
+ base.Can_change_dependent_instance_non_derived();
+
+ AssertSql(
+ @"@p3='Trek Pro Fit Madone 6 Series' (Nullable = false) (Size = 450)
+@p0='LicensedOperator' (Nullable = false) (Size = 4000)
+@p1='repairman' (Size = 4000)
+@p2='Repair' (Size = 4000)
+
+SET NOCOUNT ON;
+UPDATE [Vehicles] SET [Operator_Discriminator] = @p0, [Operator_Name] = @p1, [LicenseType] = @p2
+WHERE [Name] = @p3;
+SELECT @@ROWCOUNT;");
+ }
+
+ public override void Can_change_principal_instance_non_derived()
+ {
+ base.Can_change_principal_instance_non_derived();
+
+ AssertSql(
+ @"@p1='Trek Pro Fit Madone 6 Series' (Nullable = false) (Size = 450)
+@p0='2'
+
+SET NOCOUNT ON;
+UPDATE [Vehicles] SET [SeatingCapacity] = @p0
+WHERE [Name] = @p1;
+SELECT @@ROWCOUNT;");
+ }
+ }
+}
diff --git a/test/EFCore.Sqlite.FunctionalTests/TPTTableSplittingSqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/TPTTableSplittingSqliteTest.cs
new file mode 100644
index 00000000000..091a4d1a2b4
--- /dev/null
+++ b/test/EFCore.Sqlite.FunctionalTests/TPTTableSplittingSqliteTest.cs
@@ -0,0 +1,18 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Microsoft.EntityFrameworkCore.TestUtilities;
+using Xunit.Abstractions;
+
+namespace Microsoft.EntityFrameworkCore
+{
+ public class TPTTableSplittingSqliteTest : TPTTableSplittingTestBase
+ {
+ public TPTTableSplittingSqliteTest(ITestOutputHelper testOutputHelper)
+ : base(testOutputHelper)
+ {
+ }
+
+ protected override ITestStoreFactory TestStoreFactory => SqliteTestStoreFactory.Instance;
+ }
+}