diff --git a/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs b/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs
index 823179109e8..b13479b77c2 100644
--- a/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs
+++ b/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs
@@ -1571,6 +1571,14 @@ public InternalEntityEntry PrepareToSave()
throw new InvalidOperationException(CoreStrings.UnknownKeyValue(entityType.DisplayName(), property.Name));
}
+
+ if (property.GetElementType() != null
+ && !property.IsNullable
+ && GetCurrentValue(property) == null)
+ {
+ throw new InvalidOperationException(
+ CoreStrings.NullRequiredPrimitiveCollection(EntityType.DisplayName(), property.Name));
+ }
}
}
else if (EntityState == EntityState.Modified)
diff --git a/src/EFCore/Properties/CoreStrings.Designer.cs b/src/EFCore/Properties/CoreStrings.Designer.cs
index ffe136f9bac..1d6d20162be 100644
--- a/src/EFCore/Properties/CoreStrings.Designer.cs
+++ b/src/EFCore/Properties/CoreStrings.Designer.cs
@@ -2159,6 +2159,14 @@ public static string NullableKey(object? entityType, object? property)
GetString("NullableKey", nameof(entityType), nameof(property)),
entityType, property);
+ ///
+ /// 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.
+ ///
+ public static string NullRequiredPrimitiveCollection(object? type, object? property)
+ => string.Format(
+ GetString("NullRequiredPrimitiveCollection", nameof(type), nameof(property)),
+ type, property);
+
///
/// The object has been removed from the model.
///
diff --git a/src/EFCore/Properties/CoreStrings.resx b/src/EFCore/Properties/CoreStrings.resx
index c56b0700f52..9ba2559fe40 100644
--- a/src/EFCore/Properties/CoreStrings.resx
+++ b/src/EFCore/Properties/CoreStrings.resx
@@ -1246,6 +1246,9 @@
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.
+
+ 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.
+
The object has been removed from the model.
diff --git a/test/EFCore.Relational.Specification.Tests/TestModels/JsonQuery/JsonEntityAllTypes.cs b/test/EFCore.Relational.Specification.Tests/TestModels/JsonQuery/JsonEntityAllTypes.cs
index 8ba714be5f4..fb821d4989d 100644
--- a/test/EFCore.Relational.Specification.Tests/TestModels/JsonQuery/JsonEntityAllTypes.cs
+++ b/test/EFCore.Relational.Specification.Tests/TestModels/JsonQuery/JsonEntityAllTypes.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.ObjectModel;
+using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Microsoft.EntityFrameworkCore.TestModels.JsonQuery;
@@ -73,7 +74,10 @@ public IList TestBooleanCollection
}
public byte[] TestByteCollection { get; set; }
+
+ [Required]
public List TestGuidCollection { get; set; }
+
public IList TestUnsignedInt16Collection { get; set; }
public uint[] TestUnsignedInt32Collection { get; set; }
public ObservableCollection TestUnsignedInt64Collection { get; set; }
diff --git a/test/EFCore.Relational.Specification.Tests/Update/JsonUpdateTestBase.cs b/test/EFCore.Relational.Specification.Tests/Update/JsonUpdateTestBase.cs
index abbf5190f4e..34523ea581f 100644
--- a/test/EFCore.Relational.Specification.Tests/Update/JsonUpdateTestBase.cs
+++ b/test/EFCore.Relational.Specification.Tests/Update/JsonUpdateTestBase.cs
@@ -2971,6 +2971,21 @@ public virtual Task Edit_single_property_relational_collection_of_nullable_enum_
Assert.False(result.NewCollectionSet);
});
+ [ConditionalFact]
+ public virtual async Task SaveChanges_throws_when_required_primitive_collection_is_null()
+ => await TestHelpers.ExecuteWithStrategyInTransactionAsync(
+ CreateContext,
+ UseTransaction,
+ async context =>
+ {
+ var entity = new JsonEntityAllTypes { TestGuidCollection = null };
+ context.Add(entity);
+
+ Assert.Equal(
+ CoreStrings.NullRequiredPrimitiveCollection(nameof(JsonEntityAllTypes), nameof(JsonEntityAllTypes.TestGuidCollection)),
+ (await Assert.ThrowsAsync(async () => await context.SaveChangesAsync())).Message);
+ });
+
public void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction)
=> facade.UseTransaction(transaction.GetDbTransaction());