diff --git a/.gitignore b/.gitignore index 69367c59bdc..c5ff86be930 100644 --- a/.gitignore +++ b/.gitignore @@ -344,3 +344,4 @@ ASALocalRun/ # Local History for Visual Studio .localhistory/ +full.targets.txt diff --git a/src/EFCore.SqlServer/Design/Internal/SqlServerAnnotationCodeGenerator.cs b/src/EFCore.SqlServer/Design/Internal/SqlServerAnnotationCodeGenerator.cs index f7a5067f129..ac70e797bc5 100644 --- a/src/EFCore.SqlServer/Design/Internal/SqlServerAnnotationCodeGenerator.cs +++ b/src/EFCore.SqlServer/Design/Internal/SqlServerAnnotationCodeGenerator.cs @@ -233,17 +233,16 @@ public override IReadOnlyList GenerateFluentApiCalls( defaultValueAnnotation.Value, defaultConstraintNameAnnotation.Value)); } - else + else if (defaultValueSqlAnnotation != null) { - Check.DebugAssert( - defaultValueSqlAnnotation != null, - $"Default constraint name was set for {property.Name}, but DefaultValue and DefaultValueSql are both null."); fragments.Add( new MethodCallCodeFragment( nameof(SqlServerPropertyBuilderExtensions.HasDefaultValueSql), defaultValueSqlAnnotation.Value, defaultConstraintNameAnnotation.Value)); } + // If neither DefaultValue nor DefaultValueSql annotation exists (e.g., they were already removed + // because the default value equals the CLR default), skip generating code for the constraint name } var isPrimitiveCollection = property.IsPrimitiveCollection; diff --git a/test/EFCore.SqlServer.Tests/Design/Internal/SqlServerAnnotationCodeGeneratorTest.cs b/test/EFCore.SqlServer.Tests/Design/Internal/SqlServerAnnotationCodeGeneratorTest.cs index fffc82c1d9b..330acdea131 100644 --- a/test/EFCore.SqlServer.Tests/Design/Internal/SqlServerAnnotationCodeGeneratorTest.cs +++ b/test/EFCore.SqlServer.Tests/Design/Internal/SqlServerAnnotationCodeGeneratorTest.cs @@ -364,6 +364,33 @@ public void GenerateFluentApi_IProperty_works_with_IsSparse() } } + [ConditionalFact] + public void GenerateFluentApi_IProperty_with_DefaultConstraintName_and_no_DefaultValue_does_not_throw() + { + // Reproduces https://github.com/dotnet/efcore/issues/37175 + // When a property has a named default constraint but no DefaultValue or DefaultValueSql annotation, + // GenerateFluentApiCalls should not throw a NullReferenceException + var generator = CreateGenerator(); + var modelBuilder = SqlServerConventionSetBuilder.CreateModelBuilder(); + modelBuilder.Entity("Post", x => x.Property("Id")); + var property = modelBuilder.Model.FindEntityType("Post")!.FindProperty("Id")!; + + // Create annotations dictionary with only DefaultConstraintName (simulating the scenario where + // DefaultValue was already removed but DefaultConstraintName wasn't) + var constraintNameAnnotation = RelationalAnnotationNames.DefaultConstraintName; + var annotations = new Dictionary + { + { constraintNameAnnotation, new Annotation(constraintNameAnnotation, "DF_Post_Id") } + }; + + // This should not throw - it should simply skip generating code for the constraint name + // since there's no default value to associate with it + var result = generator.GenerateFluentApiCalls((IProperty)property, annotations); + + // No method calls should be generated for the constraint name alone + Assert.Empty(result); + } + [ConditionalFact] public void GenerateFluentApi_IModel_works_with_DatabaseMaxSize() {