Skip to content

Commit 58cca4f

Browse files
rojiAndriySvyryd
andcommitted
Implement stored procedure update mapping
Closes #245 Closes #28435 Co-authored-by: Andriy Svyryd <[email protected]>
1 parent 5e91dc3 commit 58cca4f

File tree

73 files changed

+2700
-460
lines changed

Some content is hidden

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

73 files changed

+2700
-460
lines changed

src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1153,7 +1153,7 @@ private static bool IsOptionalSharingDependent(
11531153

11541154
return optional ?? (entityType.BaseType != null && entityType.FindDiscriminatorProperty() != null);
11551155
}
1156-
1156+
11571157
/// <summary>
11581158
/// Returns the comment for the column this property is mapped to.
11591159
/// </summary>

src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,16 @@ private static void ValidateSproc(IStoredProcedure sproc, string mappingStrategy
361361
_ => new Dictionary<string, IProperty>()
362362
};
363363

364+
if (mappingStrategy == RelationalAnnotationNames.TptMappingStrategy
365+
&& storeObjectIdentifier.StoreObjectType == StoreObjectType.InsertStoredProcedure
366+
&& entityType.BaseType?.GetInsertStoredProcedure() != null)
367+
{
368+
foreach (var property in primaryKey.Properties)
369+
{
370+
storeGeneratedProperties.Remove(property.Name);
371+
}
372+
}
373+
364374
var resultColumnNames = new HashSet<string>();
365375
foreach (var resultColumn in sproc.ResultColumns)
366376
{

src/EFCore.Relational/Metadata/IColumn.cs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -147,14 +147,6 @@ bool TryGetDefaultValue(out object? defaultValue)
147147
=> PropertyMappings.First().Property
148148
.GetCollation(StoreObjectIdentifier.Table(Table.Name, Table.Schema));
149149

150-
/// <summary>
151-
/// Gets the <see cref="ValueComparer" /> for this column.
152-
/// </summary>
153-
/// <returns>The comparer.</returns>
154-
ValueComparer ProviderValueComparer
155-
=> PropertyMappings.First().Property
156-
.GetProviderValueComparer();
157-
158150
/// <summary>
159151
/// Returns the property mapping for the given entity type.
160152
/// </summary>

src/EFCore.Relational/Metadata/IColumnBase.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,14 @@ public interface IColumnBase : IAnnotatable
4646
/// </summary>
4747
IReadOnlyList<IColumnMappingBase> PropertyMappings { get; }
4848

49+
/// <summary>
50+
/// Gets the <see cref="ValueComparer" /> for this column.
51+
/// </summary>
52+
/// <returns>The comparer.</returns>
53+
ValueComparer ProviderValueComparer
54+
=> PropertyMappings.First().Property
55+
.GetProviderValueComparer();
56+
4957
/// <summary>
5058
/// Returns the property mapping for the given entity type.
5159
/// </summary>

src/EFCore.Relational/Metadata/IStoreStoredProcedureParameter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public interface IStoreStoredProcedureParameter : IColumnBase
2020
/// Gets the property mappings.
2121
/// </summary>
2222
new IReadOnlyList<IStoredProcedureParameterMapping> PropertyMappings { get; }
23-
23+
2424
/// <summary>
2525
/// Gets the direction of the parameter.
2626
/// </summary>

src/EFCore.Relational/Metadata/IStoreStoredProcedureResultColumn.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ public interface IStoreStoredProcedureResultColumn : IColumnBase
2020
/// </summary>
2121
new IReadOnlyList<IStoredProcedureResultColumnMapping> PropertyMappings { get; }
2222

23+
/// <summary>
24+
/// Gets the 0-based position of the result column in the declaring stored procedure's result set.
25+
/// </summary>
26+
int Position { get; }
27+
2328
/// <summary>
2429
/// Returns the property mapping for the given entity type.
2530
/// </summary>

src/EFCore.Relational/Metadata/Internal/JsonColumn.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ bool IColumn.IsRowVersion
148148
/// any release. You should only use it directly in your code with extreme caution and knowing that
149149
/// doing so can result in application failures when updating to a new Entity Framework Core release.
150150
/// </summary>
151-
ValueComparer IColumn.ProviderValueComparer
151+
ValueComparer IColumnBase.ProviderValueComparer
152152
=> _providerValueComparer;
153153

154154
/// <summary>

src/EFCore.Relational/Metadata/Internal/RelationalModel.cs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -960,7 +960,9 @@ private static void AddStoredProcedures(
960960
var updateStoredProcedureMappings = new List<StoredProcedureMapping>();
961961

962962
var mappingStrategy = entityType.GetMappingStrategy();
963+
var isTpt = mappingStrategy == RelationalAnnotationNames.TptMappingStrategy;
963964
var isTpc = mappingStrategy == RelationalAnnotationNames.TpcMappingStrategy;
965+
var isTph = mappingStrategy == RelationalAnnotationNames.TphMappingStrategy;
964966
while (mappedType != null)
965967
{
966968
var includesDerivedTypes = !isTpc && mappedType == entityType;
@@ -990,10 +992,12 @@ private static void AddStoredProcedures(
990992

991993
if (tableMapping != null)
992994
{
995+
Check.DebugAssert(tableMapping.InsertStoredProcedureMapping == null,
996+
"Expected sproc mapping to be unique");
993997
tableMapping.InsertStoredProcedureMapping = insertProcedureMapping;
994998
}
995999
}
996-
else if (entityType == mappedType)
1000+
else if (entityType == mappedType && !isTpt)
9971001
{
9981002
insertStoredProcedureMappings = null;
9991003
}
@@ -1014,10 +1018,12 @@ private static void AddStoredProcedures(
10141018

10151019
if (tableMapping != null)
10161020
{
1021+
Check.DebugAssert(tableMapping.DeleteStoredProcedureMapping == null,
1022+
"Expected sproc mapping to be unique");
10171023
tableMapping.DeleteStoredProcedureMapping = deleteProcedureMapping;
10181024
}
10191025
}
1020-
else if (entityType == mappedType)
1026+
else if (entityType == mappedType && !isTpt)
10211027
{
10221028
deleteStoredProcedureMappings = null;
10231029
}
@@ -1038,15 +1044,17 @@ private static void AddStoredProcedures(
10381044

10391045
if (tableMapping != null)
10401046
{
1047+
Check.DebugAssert(tableMapping.UpdateStoredProcedureMapping == null,
1048+
"Expected sproc mapping to be unique");
10411049
tableMapping.UpdateStoredProcedureMapping = updateProcedureMapping;
10421050
}
10431051
}
1044-
else if (entityType == mappedType)
1052+
else if (entityType == mappedType && !isTpt)
10451053
{
10461054
updateStoredProcedureMappings = null;
10471055
}
10481056

1049-
if (isTpc || mappingStrategy == RelationalAnnotationNames.TphMappingStrategy)
1057+
if (isTpc || isTph)
10501058
{
10511059
break;
10521060
}
@@ -1169,13 +1177,16 @@ private static StoredProcedureMapping CreateStoredProcedureMapping(
11691177
columnMappings.Add(columnMapping);
11701178
}
11711179

1180+
position = -1;
11721181
foreach (var resultColumn in storedProcedure.ResultColumns)
11731182
{
1183+
position++;
11741184
if (resultColumn.PropertyName == null)
11751185
{
11761186
GetOrCreateStoreStoredProcedureResultColumn(
11771187
resultColumn,
11781188
null,
1189+
position,
11791190
storeStoredProcedure,
11801191
identifier,
11811192
relationalTypeMappingSource);
@@ -1199,6 +1210,7 @@ private static StoredProcedureMapping CreateStoredProcedureMapping(
11991210
GetOrCreateStoreStoredProcedureResultColumn(
12001211
resultColumn,
12011212
derivedProperty,
1213+
position,
12021214
storeStoredProcedure,
12031215
identifier,
12041216
relationalTypeMappingSource);
@@ -1213,6 +1225,7 @@ private static StoredProcedureMapping CreateStoredProcedureMapping(
12131225
var column = GetOrCreateStoreStoredProcedureResultColumn(
12141226
resultColumn,
12151227
property,
1228+
position,
12161229
storeStoredProcedure,
12171230
identifier,
12181231
relationalTypeMappingSource);
@@ -1320,6 +1333,7 @@ static StoreStoredProcedureParameter GetOrCreateStoreStoredProcedureParameter(
13201333
static StoreStoredProcedureResultColumn GetOrCreateStoreStoredProcedureResultColumn(
13211334
IStoredProcedureResultColumn resultColumn,
13221335
IProperty? property,
1336+
int position,
13231337
StoreStoredProcedure storeStoredProcedure,
13241338
StoreObjectIdentifier identifier,
13251339
IRelationalTypeMappingSource relationalTypeMappingSource)
@@ -1334,13 +1348,16 @@ static StoreStoredProcedureResultColumn GetOrCreateStoreStoredProcedureResultCol
13341348
column = new StoreStoredProcedureResultColumn(
13351349
name,
13361350
typeMapping.StoreType,
1337-
storeStoredProcedure);
1351+
position,
1352+
storeStoredProcedure,
1353+
typeMapping);
13381354
}
13391355
else
13401356
{
13411357
column = new StoreStoredProcedureResultColumn(
13421358
name,
13431359
property.GetColumnType(identifier),
1360+
position,
13441361
storeStoredProcedure)
13451362
{
13461363
IsNullable = property.IsColumnNullable(identifier)

src/EFCore.Relational/Metadata/Internal/StoreStoredProcedureResultColumn.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@ public class StoreStoredProcedureResultColumn
2323
public StoreStoredProcedureResultColumn(
2424
string name,
2525
string type,
26+
int position,
2627
StoreStoredProcedure storedProcedure,
2728
RelationalTypeMapping? storeTypeMapping = null)
2829
: base(name, type, storedProcedure)
2930
{
31+
Position = position;
3032
_storeTypeMapping = storeTypeMapping;
3133
}
3234

@@ -38,7 +40,15 @@ public StoreStoredProcedureResultColumn(
3840
/// </summary>
3941
public virtual StoreStoredProcedure StoredProcedure
4042
=> (StoreStoredProcedure)Table;
41-
43+
44+
/// <summary>
45+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
46+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
47+
/// any release. You should only use it directly in your code with extreme caution and knowing that
48+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
49+
/// </summary>
50+
public virtual int Position { get; }
51+
4252
/// <summary>
4353
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
4454
/// the same compatibility standards as public APIs. It may be changed or removed without notice in

src/EFCore.Relational/Migrations/Internal/MigrationsModelDiffer.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2073,7 +2073,9 @@ protected virtual void DiffData(
20732073
var anyColumnsModified = false;
20742074
foreach (var targetColumnModification in targetRow.ColumnModifications)
20752075
{
2076-
var targetColumn = targetColumnModification.Column!;
2076+
var targetColumnBase = targetColumnModification.Column!;
2077+
Check.DebugAssert(targetColumnBase is IColumn, "Non-IColumn columns not allowed");
2078+
var targetColumn = (IColumn)targetColumnBase;
20772079
var targetMapping = targetColumn.PropertyMappings.First();
20782080
var targetProperty = targetMapping.Property;
20792081

@@ -2281,7 +2283,7 @@ private IEnumerable<MigrationOperation> GetDataOperations(
22812283
Check.DebugAssert(forSource, "Delete using the target model");
22822284

22832285
var keyColumns = command.ColumnModifications.Where(col => col.IsKey)
2284-
.Select(c => c.Column!);
2286+
.Select(c => (IColumn)c.Column!);
22852287
var anyKeyColumnDropped = keyColumns.Any(c => diffContext.FindDrop(c) != null);
22862288

22872289
yield return new DeleteDataOperation

0 commit comments

Comments
 (0)