Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Fix the exception message for value generated key properties without a value generator #35422

Open
damieng opened this issue Jan 7, 2025 · 1 comment

Comments

@damieng
Copy link

damieng commented Jan 7, 2025

Previously in EF 8 if you set a property on an entity to an explicit value then it did not matter that there was no value generator available for it.

In EF9 it now throws on Add with the error message

The property 'MyEntity.Id' does not have a value set and no value generator is available for properties of type 'int'. Either set a value for the property before adding the entity or configure a value generator for properties of type 'int' in 'OnModelCreating'.

Despite the property having a value explicitly set.

Repro

Minimal repro using InMemoryDatabase with an override to prevent a value generator from being found for integer:

using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.InMemory.Storage.Internal;
using Microsoft.EntityFrameworkCore.InMemory.ValueGeneration.Internal;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.ValueGeneration;

var options = new DbContextOptionsBuilder()
    .ReplaceService<IValueGeneratorSelector, IntlessValueGeneratorSelector>()
    .UseInMemoryDatabase(Guid.NewGuid().ToString())
    .Options;

var context = new MyContext(options);
var newEntity = new MyEntity { Id = 1, Name = "Test"};
context.Add(newEntity);

class MyContext(DbContextOptions options) : DbContext(options)
{
    public DbSet<MyEntity> Entities { get; set; }
}

class MyEntity
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }
}

class IntlessValueGeneratorSelector : InMemoryValueGeneratorSelector
{
    public IntlessValueGeneratorSelector(ValueGeneratorSelectorDependencies dependencies, IInMemoryDatabase inMemoryDatabase)
        : base(dependencies, inMemoryDatabase)
    {
    }

    public override bool TrySelect(IProperty property, ITypeBase typeBase, out ValueGenerator? valueGenerator)
    {
        valueGenerator = null;
        if (property.ClrType == typeof(int)) return false;
        return base.TrySelect(property, typeBase, out valueGenerator);
    }

}

Stack traces

Unhandled exception. System.NotSupportedException: The property 'MyEntity.Id' does not have a value set and no value generator is available for properties of type 'int'. Either set a value for the property before adding the entity or configure a value generator for properties of type 'int' in 'OnModelCreating'.
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.ValueGenerationManager.CheckPropertyWithNoGenerator(IProperty property)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.ValueGenerationManager.Generate(InternalEntityEntry entry, Boolean includePrimaryKey)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState entityState, Boolean acceptChanges, Boolean modifyProperties, Nullable`1 forceStateWhenUnknownKey, Nullable`1 fallbackState)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.PaintAction(EntityEntryGraphNode`1 node)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityEntryGraphIterator.TraverseGraph[TState](EntityEntryGraphNode`1 node, Func`2 handleNode)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.AttachGraph(InternalEntityEntry rootEntry, EntityState targetState, EntityState storeGeneratedWithKeySetTargetState, Boolean forceStateWhenUnknownKey)
   at Microsoft.EntityFrameworkCore.DbContext.SetEntityState(InternalEntityEntry entry, EntityState entityState)
   at Microsoft.EntityFrameworkCore.DbContext.SetEntityState[TEntity](TEntity entity, EntityState entityState)
   at Microsoft.EntityFrameworkCore.DbContext.Add[TEntity](TEntity entity)
   at Program.<Main>$(String[] args) in E:\src\temp\SetGeneratedRepro\SetGeneratedRepro\Program.cs:line 16

Povider and version information

EF Core version: 9.0.0
Database provider: All
Target framework: .NET 8.0
Operating system: Windows
IDE: Rider 2404.3.3

Additional notes

I believe this was unintentionally introduced in 838ae11#diff-b9fdb780a381b36843749313b829bf2164ad758390d555891f75f05c0ce2c365R215 and was not caught in tests because all the built-in providers now provide a value generator for integers.

Specifically EF9 is now only checking entry.HasExplicitCheck after it has already decided that the property is problematic in TryFindValueGenerator.

Possible fix

It's possible that the HasExplicitCheck needs to happen before the GetContainingKeysCheck although I'm not entirely sure what that block is trying to achieve.

@AndriySvyryd
Copy link
Member

@damieng While this could be seen as a regression, this is definitely an intentional change, see the test at 838ae11#diff-eab1e69f8bb78fa95c369fa2f8dea5d206eda5b3beda3b980d6366cf761346f2R197

I think that the intention of this check is to indicate that a key property that doesn't have an associated value generator shouldn't be marked as ValueGenerated.OnAdd.

In particular, providers that don't support value generation for a particular type should override https://github.com/dotnet/efcore/blob/main/src/EFCore/Metadata/Conventions/ValueGenerationConvention.cs#L183 to avoid marking properties of that type as ValueGenerated.OnAdd by convention.

@AndriySvyryd AndriySvyryd closed this as not planned Won't fix, can't repro, duplicate, stale Jan 8, 2025
@AndriySvyryd AndriySvyryd reopened this Jan 8, 2025
@AndriySvyryd AndriySvyryd changed the title New entities throw on Add when they have explicit set properties and no value generator Fix the exception message for value generated key properties without a value generator Jan 8, 2025
@AndriySvyryd AndriySvyryd added this to the Backlog milestone Jan 8, 2025
# for free to join this conversation on GitHub. Already have an account? # to comment
Projects
None yet
Development

No branches or pull requests

3 participants