Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -700,26 +700,26 @@ private static ColumnExpression CreateColumnExpression(
string tableAlias,
bool nullable)
=> new(
column,
column.Name,
tableAlias,
column,
property.ClrType.UnwrapNullableType(),
column.PropertyMappings.First(m => m.Property == property).TypeMapping,
nullable);
nullable || column.IsNullable);

private static ColumnExpression CreateColumnExpression(ProjectionExpression subqueryProjection, string tableAlias)
=> subqueryProjection.Expression is ColumnExpression { Column: IColumnBase column, TypeMapping: RelationalTypeMapping typeMapping } columnExpression
? new(column, tableAlias, columnExpression.Type, typeMapping, columnExpression.IsNullable)
: new(
subqueryProjection.Alias,
tableAlias,
subqueryProjection.Type,
subqueryProjection.Expression.TypeMapping!,
subqueryProjection.Expression switch
{
ColumnExpression c => c.IsNullable,
SqlConstantExpression c => c.Value is null,
_ => true
});
=> new(
subqueryProjection.Alias,
tableAlias,
column: subqueryProjection.Expression is ColumnExpression { Column: IColumnBase column } ? column : null,
subqueryProjection.Type,
subqueryProjection.Expression.TypeMapping!,
subqueryProjection.Expression switch
{
ColumnExpression c => c.IsNullable,
SqlConstantExpression c => c.Value is null,
_ => true
});

private static ColumnExpression CreateColumnExpression(
TableExpressionBase tableExpression,
Expand Down
19 changes: 9 additions & 10 deletions src/EFCore.Relational/Query/SqlExpressions/ColumnExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,33 +31,32 @@ public ColumnExpression(
Type type,
RelationalTypeMapping? typeMapping,
bool nullable)
: base(type, typeMapping)
: this(name, tableAlias, column: null, type, typeMapping, nullable)
{
Name = name;
TableAlias = tableAlias;
IsNullable = nullable;
}

/// <summary>
/// Creates a new instance of the <see cref="ColumnExpression" /> class.
/// </summary>
/// <param name="column">The <see cref="IColumnBase" /> associated with this column expression.</param>
/// <param name="name">The name of the column.</param>
/// <param name="tableAlias">The alias of the table to which this column refers.</param>
/// <param name="column">An optional <see cref="IColumnBase" /> associated with this column expression.</param>
/// <param name="type">The <see cref="System.Type" /> of the expression.</param>
/// <param name="typeMapping">The <see cref="RelationalTypeMapping" /> associated with the expression.</param>
/// <param name="nullable">Whether this expression represents a nullable column.</param>
[EntityFrameworkInternal]
public ColumnExpression(
IColumnBase column,
string name,
string tableAlias,
IColumnBase? column,
Type type,
RelationalTypeMapping typeMapping,
RelationalTypeMapping? typeMapping,
bool nullable)
: base(type, typeMapping)
{
Name = column.Name;
Name = name;
TableAlias = tableAlias;
IsNullable = nullable || column.IsNullable;
Column = column;
IsNullable = nullable;
}

/// <summary>
Expand Down
125 changes: 67 additions & 58 deletions src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1232,64 +1232,73 @@ Expression CopyProjectionToOuter(SelectExpression innerSelectExpression, Express
{
var constantValue = ((ConstantExpression)innerSelectExpression._clientProjections[j]).Value!;
ConstantExpression remappedConstant;
if (constantValue is Dictionary<IProperty, int> entityDictionary)
switch (((ConstantExpression)innerSelectExpression._clientProjections[j]).Value!)
{
var newDictionary = new Dictionary<IProperty, int>(entityDictionary.Count);
foreach (var (property, value) in entityDictionary)
case Dictionary<IProperty, int> entityDictionary:
{
newDictionary[property] = projectionIndexMap[value];
}

remappedConstant = Constant(newDictionary);
}
else if (constantValue is JsonProjectionInfo jsonProjectionInfo)
{
var newKeyAccessInfo = new List<(IProperty?, int?, int?)>();
foreach (var (keyProperty, constantKeyValue, keyProjectionIndex) in jsonProjectionInfo.KeyAccessInfo)
{
newKeyAccessInfo.Add(
(keyProperty, constantKeyValue,
keyProjectionIndex != null ? projectionIndexMap[keyProjectionIndex.Value] : null));
}
var newDictionary = new Dictionary<IProperty, int>(entityDictionary.Count);
foreach (var (property, value) in entityDictionary)
{
newDictionary[property] = projectionIndexMap[value];
}

remappedConstant = Constant(
new JsonProjectionInfo(
projectionIndexMap[jsonProjectionInfo.JsonColumnIndex],
newKeyAccessInfo));
}
else if (constantValue is QueryableJsonProjectionInfo queryableJsonProjectionInfo)
{
var newPropertyIndexMap = new Dictionary<IProperty, int>(queryableJsonProjectionInfo.PropertyIndexMap.Count);
foreach (var (property, value) in queryableJsonProjectionInfo.PropertyIndexMap)
{
newPropertyIndexMap[property] = projectionIndexMap[value];
remappedConstant = Constant(newDictionary);
break;
}

var newChildrenProjectionInfo = new List<(JsonProjectionInfo, INavigation)>();
foreach (var childProjectionInfo in queryableJsonProjectionInfo.ChildrenProjectionInfo)
case JsonProjectionInfo jsonProjectionInfo:
{
var newKeyAccessInfo = new List<(IProperty?, int?, int?)>();
foreach (var (keyProperty, constantKeyValue, keyProjectionIndex) in childProjectionInfo.JsonProjectionInfo
.KeyAccessInfo)
foreach (var (keyProperty, constantKeyValue, keyProjectionIndex) in jsonProjectionInfo.KeyAccessInfo)
{
newKeyAccessInfo.Add(
(keyProperty, constantKeyValue,
keyProjectionIndex != null ? projectionIndexMap[keyProjectionIndex.Value] : null));
}

newChildrenProjectionInfo.Add(
(new JsonProjectionInfo(
projectionIndexMap[childProjectionInfo.JsonProjectionInfo.JsonColumnIndex],
newKeyAccessInfo),
childProjectionInfo.Navigation));
remappedConstant = Constant(
new JsonProjectionInfo(
projectionIndexMap[jsonProjectionInfo.JsonColumnIndex],
newKeyAccessInfo));
break;
}

remappedConstant = Constant(
new QueryableJsonProjectionInfo(newPropertyIndexMap, newChildrenProjectionInfo));
}
else
{
remappedConstant = Constant(projectionIndexMap[(int)constantValue]);
case QueryableJsonProjectionInfo queryableJsonProjectionInfo:
{
var newPropertyIndexMap = new Dictionary<IProperty, int>(queryableJsonProjectionInfo.PropertyIndexMap.Count);
foreach (var (property, value) in queryableJsonProjectionInfo.PropertyIndexMap)
{
newPropertyIndexMap[property] = projectionIndexMap[value];
}

var newChildrenProjectionInfo = new List<(JsonProjectionInfo, INavigation)>();
foreach (var childProjectionInfo in queryableJsonProjectionInfo.ChildrenProjectionInfo)
{
var newKeyAccessInfo = new List<(IProperty?, int?, int?)>();
foreach (var (keyProperty, constantKeyValue, keyProjectionIndex) in childProjectionInfo.JsonProjectionInfo
.KeyAccessInfo)
{
newKeyAccessInfo.Add(
(keyProperty, constantKeyValue,
keyProjectionIndex != null ? projectionIndexMap[keyProjectionIndex.Value] : null));
}

newChildrenProjectionInfo.Add(
(new JsonProjectionInfo(
projectionIndexMap[childProjectionInfo.JsonProjectionInfo.JsonColumnIndex],
newKeyAccessInfo),
childProjectionInfo.Navigation));
}

remappedConstant = Constant(
new QueryableJsonProjectionInfo(newPropertyIndexMap, newChildrenProjectionInfo));

break;
}

default:
remappedConstant = Constant(projectionIndexMap[(int)constantValue]);
break;
}

newClientProjections.Add(remappedConstant);
Expand Down Expand Up @@ -4031,26 +4040,26 @@ private static ColumnExpression CreateColumnExpression(
string tableAlias,
bool nullable)
=> new(
column,
column.Name,
tableAlias,
column,
property.ClrType.UnwrapNullableType(),
column.PropertyMappings.First(m => m.Property == property).TypeMapping,
nullable);
nullable || column.IsNullable);

private static ColumnExpression CreateColumnExpression(ProjectionExpression subqueryProjection, string tableAlias)
=> subqueryProjection.Expression is ColumnExpression { Column: IColumnBase column, TypeMapping: RelationalTypeMapping typeMapping } columnExpression
? new(column, tableAlias, columnExpression.Type, typeMapping, columnExpression.IsNullable)
: new(
subqueryProjection.Alias,
tableAlias,
subqueryProjection.Type,
subqueryProjection.Expression.TypeMapping!,
subqueryProjection.Expression switch
{
ColumnExpression c => c.IsNullable,
SqlConstantExpression c => c.Value is null,
_ => true
});
=> new(
subqueryProjection.Alias,
tableAlias,
column: subqueryProjection.Expression is ColumnExpression { Column: IColumnBase column } ? column : null,
subqueryProjection.Type,
subqueryProjection.Expression.TypeMapping!,
subqueryProjection.Expression switch
{
ColumnExpression c => c.IsNullable,
SqlConstantExpression c => c.Value is null,
_ => true
});

private ColumnExpression GenerateOuterColumn(
string tableAlias,
Expand Down