Skip to content

Commit 0d590c8

Browse files
authored
Throw if required primitive collection is null when saving changes (#31521)
1 parent 4a976b7 commit 0d590c8

File tree

5 files changed

+38
-0
lines changed

5 files changed

+38
-0
lines changed

src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1571,6 +1571,14 @@ public InternalEntityEntry PrepareToSave()
15711571

15721572
throw new InvalidOperationException(CoreStrings.UnknownKeyValue(entityType.DisplayName(), property.Name));
15731573
}
1574+
1575+
if (property.GetElementType() != null
1576+
&& !property.IsNullable
1577+
&& GetCurrentValue(property) == null)
1578+
{
1579+
throw new InvalidOperationException(
1580+
CoreStrings.NullRequiredPrimitiveCollection(EntityType.DisplayName(), property.Name));
1581+
}
15741582
}
15751583
}
15761584
else if (EntityState == EntityState.Modified)

src/EFCore/Properties/CoreStrings.Designer.cs

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/EFCore/Properties/CoreStrings.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,6 +1246,9 @@
12461246
<data name="NullableKey" xml:space="preserve">
12471247
<value>A key on entity type '{entityType}' cannot contain the property '{property}' because it is nullable/optional. All properties on which a key is declared must be marked as non-nullable/required.</value>
12481248
</data>
1249+
<data name="NullRequiredPrimitiveCollection" xml:space="preserve">
1250+
<value>The primitive collection property '{type}.{property}' is configured as required (non-nullable) but has a null value when saving changes. Either mark the property as optional (nullable) or set a non-null value.</value>
1251+
</data>
12491252
<data name="ObjectRemovedFromModel" xml:space="preserve">
12501253
<value>The object has been removed from the model.</value>
12511254
</data>

test/EFCore.Relational.Specification.Tests/TestModels/JsonQuery/JsonEntityAllTypes.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Collections.ObjectModel;
5+
using System.ComponentModel.DataAnnotations;
56
using System.ComponentModel.DataAnnotations.Schema;
67

78
namespace Microsoft.EntityFrameworkCore.TestModels.JsonQuery;
@@ -73,7 +74,10 @@ public IList<bool> TestBooleanCollection
7374
}
7475

7576
public byte[] TestByteCollection { get; set; }
77+
78+
[Required]
7679
public List<Guid> TestGuidCollection { get; set; }
80+
7781
public IList<ushort> TestUnsignedInt16Collection { get; set; }
7882
public uint[] TestUnsignedInt32Collection { get; set; }
7983
public ObservableCollection<ulong> TestUnsignedInt64Collection { get; set; }

test/EFCore.Relational.Specification.Tests/Update/JsonUpdateTestBase.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2971,6 +2971,21 @@ public virtual Task Edit_single_property_relational_collection_of_nullable_enum_
29712971
Assert.False(result.NewCollectionSet);
29722972
});
29732973

2974+
[ConditionalFact]
2975+
public virtual async Task SaveChanges_throws_when_required_primitive_collection_is_null()
2976+
=> await TestHelpers.ExecuteWithStrategyInTransactionAsync(
2977+
CreateContext,
2978+
UseTransaction,
2979+
async context =>
2980+
{
2981+
var entity = new JsonEntityAllTypes { TestGuidCollection = null };
2982+
context.Add(entity);
2983+
2984+
Assert.Equal(
2985+
CoreStrings.NullRequiredPrimitiveCollection(nameof(JsonEntityAllTypes), nameof(JsonEntityAllTypes.TestGuidCollection)),
2986+
(await Assert.ThrowsAsync<InvalidOperationException>(async () => await context.SaveChangesAsync())).Message);
2987+
});
2988+
29742989
public void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction)
29752990
=> facade.UseTransaction(transaction.GetDbTransaction());
29762991

0 commit comments

Comments
 (0)