Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit c49a522

Browse files
committedJan 29, 2025·
Add support for primitive collections to the compiled model
Fixes #35047
1 parent 4458035 commit c49a522

File tree

71 files changed

+21540
-97
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+21540
-97
lines changed
 

‎src/EFCore.Design/Scaffolding/Internal/CSharpRuntimeModelCodeGenerator.cs

+142-13
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
77
using Microsoft.EntityFrameworkCore.Design.Internal;
88
using Microsoft.EntityFrameworkCore.Internal;
9+
using Microsoft.EntityFrameworkCore.Metadata;
910
using Microsoft.EntityFrameworkCore.Metadata.Internal;
1011
using Microsoft.EntityFrameworkCore.Query.Internal;
1112

@@ -1179,18 +1180,7 @@ private void Create(
11791180
var valueComparerType = (Type?)property[CoreAnnotationNames.ValueComparerType];
11801181
if (valueComparerType != null)
11811182
{
1182-
AddNamespace(valueComparerType, parameters.Namespaces);
1183-
1184-
var valueComparerString = $"new {_code.Reference(valueComparerType)}()";
1185-
if (property.ClrType.IsNullableValueType())
1186-
{
1187-
var valueComparerElementType = ((ValueComparer)Activator.CreateInstance(valueComparerType)!).Type;
1188-
if (!valueComparerElementType.IsNullableValueType())
1189-
{
1190-
AddNamespace(typeof(NullableValueComparer<>), parameters.Namespaces);
1191-
valueComparerString = $"new NullableValueComparer<{_code.Reference(valueComparerType)}>({valueComparerString})";
1192-
}
1193-
}
1183+
var valueComparerString = CreateValueComparerType(valueComparerType, property.ClrType, parameters);
11941184

11951185
mainBuilder.AppendLine(",")
11961186
.Append("valueComparer: ")
@@ -1240,11 +1230,13 @@ private void Create(
12401230
&& converter != null
12411231
&& property[CoreAnnotationNames.ValueConverter] != null
12421232
&& !parameters.ForNativeAot;
1233+
var typeMappingSet = false;
12431234

12441235
if (parameters.ForNativeAot
12451236
|| (shouldSetConverter && converter!.MappingHints != null))
12461237
{
12471238
shouldSetConverter = false;
1239+
typeMappingSet = true;
12481240
mainBuilder.Append(variableName).Append(".TypeMapping = ");
12491241
_annotationCodeGenerator.Create(property.GetTypeMapping(), property, propertyParameters);
12501242
mainBuilder.AppendLine(";");
@@ -1311,14 +1303,151 @@ private void Create(
13111303
.AppendLine(");");
13121304
}
13131305

1306+
var elementType = property.GetElementType();
1307+
if (elementType != null)
1308+
{
1309+
Check.DebugAssert(property.IsPrimitiveCollection, $"{property.Name} has an element type, but it's not a primitive collection.");
1310+
Create(elementType, typeMappingSet, propertyParameters);
1311+
}
1312+
13141313
CreateAnnotations(
13151314
property,
13161315
_annotationCodeGenerator.Generate,
1317-
parameters with { TargetName = variableName });
1316+
propertyParameters);
13181317

13191318
mainBuilder.AppendLine();
13201319
}
13211320

1321+
private void Create(IElementType elementType, bool typeMappingSet, CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
1322+
{
1323+
var mainBuilder = parameters.MainBuilder;
1324+
var elementVariableName = _code.Identifier(parameters.TargetName + "ElementType", elementType, parameters.ScopeObjects, capitalize: false);
1325+
var elementParameters = parameters with { TargetName = elementVariableName };
1326+
1327+
mainBuilder
1328+
.Append("var ").Append(elementVariableName).Append(" = ")
1329+
.Append(parameters.TargetName).Append(".SetElementType(").IncrementIndent()
1330+
.Append(_code.Literal(elementType.ClrType));
1331+
1332+
if (elementType.IsNullable)
1333+
{
1334+
mainBuilder.AppendLine(",")
1335+
.Append("nullable: ")
1336+
.Append(_code.Literal(elementType.IsNullable));
1337+
}
1338+
1339+
if (elementType.GetMaxLength() != null)
1340+
{
1341+
mainBuilder.AppendLine(",")
1342+
.Append("maxLength: ")
1343+
.Append(_code.Literal(elementType.GetMaxLength()));
1344+
}
1345+
1346+
if (elementType.IsUnicode() != null)
1347+
{
1348+
mainBuilder.AppendLine(",")
1349+
.Append("unicode: ")
1350+
.Append(_code.Literal(elementType.IsUnicode()));
1351+
}
1352+
1353+
if (elementType.GetPrecision() != null)
1354+
{
1355+
mainBuilder.AppendLine(",")
1356+
.Append("precision: ")
1357+
.Append(_code.Literal(elementType.GetPrecision()));
1358+
}
1359+
1360+
if (elementType.GetScale() != null)
1361+
{
1362+
mainBuilder.AppendLine(",")
1363+
.Append("scale: ")
1364+
.Append(_code.Literal(elementType.GetScale()));
1365+
}
1366+
1367+
var providerClrType = elementType.GetProviderClrType();
1368+
if (providerClrType != null)
1369+
{
1370+
AddNamespace(providerClrType, parameters.Namespaces);
1371+
mainBuilder.AppendLine(",")
1372+
.Append("providerClrType: ")
1373+
.Append(_code.Literal(providerClrType));
1374+
}
1375+
1376+
var jsonValueReaderWriterType = (Type?)elementType[CoreAnnotationNames.JsonValueReaderWriterType];
1377+
if (jsonValueReaderWriterType != null)
1378+
{
1379+
mainBuilder.AppendLine(",")
1380+
.Append("jsonValueReaderWriter: ");
1381+
CSharpRuntimeAnnotationCodeGenerator.CreateJsonValueReaderWriter(jsonValueReaderWriterType, parameters, _code);
1382+
}
1383+
1384+
mainBuilder
1385+
.AppendLine(");")
1386+
.DecrementIndent();
1387+
1388+
var converter = elementType.FindTypeMapping()?.Converter;
1389+
var shouldSetConverter = providerClrType == null
1390+
&& converter != null
1391+
&& elementType[CoreAnnotationNames.ValueConverter] != null
1392+
&& !parameters.ForNativeAot;
1393+
1394+
if (parameters.ForNativeAot
1395+
|| (shouldSetConverter && converter!.MappingHints != null))
1396+
{
1397+
shouldSetConverter = false;
1398+
mainBuilder.Append(elementVariableName).Append(".TypeMapping = ");
1399+
1400+
if (typeMappingSet)
1401+
{
1402+
mainBuilder.Append(parameters.TargetName).Append(".TypeMapping.ElementTypeMapping");
1403+
}
1404+
else
1405+
{
1406+
_annotationCodeGenerator.Create(elementType.GetTypeMapping(), elementParameters);
1407+
}
1408+
1409+
mainBuilder.AppendLine(";");
1410+
}
1411+
1412+
if (shouldSetConverter)
1413+
{
1414+
mainBuilder.Append(elementVariableName).Append(".SetValueConverter(");
1415+
_annotationCodeGenerator.Create(converter!, parameters);
1416+
mainBuilder.AppendLine(");");
1417+
}
1418+
1419+
var valueComparer = elementType.GetValueComparer();
1420+
var typeMappingComparer = elementType.GetTypeMapping().Comparer;
1421+
if ((!parameters.ForNativeAot || valueComparer != typeMappingComparer)
1422+
&& (parameters.ForNativeAot || elementType[CoreAnnotationNames.ValueComparer] != null))
1423+
{
1424+
SetValueComparer(valueComparer, typeMappingComparer, nameof(CoreTypeMapping.Comparer), elementParameters);
1425+
}
1426+
1427+
CreateAnnotations(
1428+
elementType,
1429+
_annotationCodeGenerator.Generate,
1430+
elementParameters);
1431+
}
1432+
1433+
private string CreateValueComparerType(Type valueComparerType, Type clrType, CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
1434+
{
1435+
AddNamespace(valueComparerType, parameters.Namespaces);
1436+
1437+
var valueComparerString = $"new {_code.Reference(valueComparerType)}()";
1438+
if (clrType.IsNullableValueType())
1439+
{
1440+
var valueComparerElementType = ((ValueComparer)Activator.CreateInstance(valueComparerType)!).Type;
1441+
if (!valueComparerElementType.IsNullableValueType())
1442+
{
1443+
AddNamespace(typeof(NullableValueComparer<>), parameters.Namespaces);
1444+
valueComparerString = $"new NullableValueComparer<{_code.Reference(valueComparerType)}>({valueComparerString})";
1445+
}
1446+
}
1447+
1448+
return valueComparerString;
1449+
}
1450+
13221451
private void SetValueComparer(
13231452
ValueComparer valueComparer,
13241453
ValueComparer typeMappingComparer,

‎src/EFCore.Relational/Storage/RelationalTypeMapping.cs

-6
Original file line numberDiff line numberDiff line change
@@ -572,12 +572,6 @@ public virtual DbParameter CreateParameter(
572572

573573
if (nullable.HasValue)
574574
{
575-
Check.DebugAssert(
576-
nullable.Value
577-
|| !direction.HasFlag(ParameterDirection.Input)
578-
|| value != null,
579-
"Null value in a non-nullable input parameter");
580-
581575
parameter.IsNullable = nullable.Value;
582576
}
583577

0 commit comments

Comments
 (0)