When adding seed data to an entity which also has ForNpgsqlUseXminAsConcurrencyToken enabled this fails at migration scaffolding time with the error:
This is not a value that's available on the model to be set and I've tried all the HasDefaultValue and other metadata flags to no avail so I'm not entirely sure how to proceed.
System.InvalidOperationException: The seed entity for entity type 'IdentityRole<int>' cannot be added because there was no value provided for the required property 'xmin'.
at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.ValidateData(IModel model)
at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.Validate(IModel model)
at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.Validate(IModel model)
at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder, IModelValidator validator)
at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
at System.Lazy`1.CreateValue()
at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel()
at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
at Microsoft.EntityFrameworkCore.Internal.InternalAccessorExtensions.GetService[TService](IInfrastructure`1 accessor)
at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(Func`1 factory)
at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(String contextType)
at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
After some investigation, this seems to be a limitation of how the seeding feature works in EF Core itself.
In https://github.com/aspnet/EntityFrameworkCore/issues/12167 (and also in https://github.com/aspnet/EntityFrameworkCore/issues/12080), people attempt to seed data without specifying ID values, expecting them to be store-generated, but this isn't supported by seeding. This is also mentioned in the seeding docs, although I think this point could actually be clarified a little (including techniques for explicitly seeding ID values without causing conflicts, i.e. explicitly seeding negative ID values).
The same issue occurs with xmin as a concurrency token - it's very similar to IDs in that its store-generated (ValueGeneratedOnAddOrUpdate), and I suspect the same issue will occur with SQL Server rowversion. However, the PostgreSQL situation is more problematic because in PostgreSQL the xmin column is a special system column which only the database can set - so we can't work around this by supplying values when seeding (which I'm guessing is what you do with SQL Server rowversion columns).
@ajcvickers can you confirm the above? Is there any issue which tracks allowing store-generated values while seeding? If not should I open an issue in your repo for this?
This is certainly related to other issues we have seen but I don't remember if we have this particular case tracked. @AndriySvyryd can likely confirm.
The closest issue is probably https://github.com/aspnet/EntityFrameworkCore/issues/12525 where we will ensure that the value doesn't need to be provided for non-key properties that are store generated.
OK, closing this as an EF Core-side issue, thanks!
@NinoFloris now that 2.2 has RTMed, can you give it a test and confirm that the issue is gone?
Zero change
System.InvalidOperationException: The seed entity for entity type 'IdentityRole<int>' cannot be added because there was no value provided for the required property 'xmin'.
at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.ValidateData(IModel model)
at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.Validate(IModel model)
at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.Validate(IModel model)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ValidatingConvention.Apply(InternalModelBuilder modelBuilder)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelBuilt(InternalModelBuilder modelBuilder)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnModelBuilt(InternalModelBuilder modelBuilder)
at Microsoft.EntityFrameworkCore.Metadata.Internal.Model.Validate()
at Microsoft.EntityFrameworkCore.ModelBuilder.FinalizeModel()
at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder, IModelValidator validator)
at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.<>c__DisplayClass5_0.<GetModel>b__1()
at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
at System.Lazy`1.CreateValue()
at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder, IModelValidator validator)
at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel()
at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__7_2(IServiceProvider p)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
at Microsoft.EntityFrameworkCore.DbContext.Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure<System.IServiceProvider>.get_Instance()
at Microsoft.EntityFrameworkCore.Internal.InternalAccessorExtensions.GetService[TService](IInfrastructure`1 accessor)
at Microsoft.EntityFrameworkCore.Infrastructure.AccessorExtensions.GetService[TService](IInfrastructure`1 accessor)
at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(Func`1 factory)
at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(String contextType)
at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_1.<.ctor>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
The seed entity for entity type 'IdentityRole<int>' cannot be added because there was no value provided for the required property 'xmin'.
@NinoFloris As a workaround you could set a value generator:
```C#
using Microsoft.EntityFrameworkCore.ValueGeneration.Internal
e.Property(a => a.xmin).ValueGeneratedOnAddOrUpdate()
.HasValueGenerator((_, __) => new StringValueGenerator(generateTemporaryValues: true));
```
@AndriySvyryd thanks for the suggestion.
Changing your suggestion to match the correct semantics like so:
builder.Entity<IdentityRole<int>>(b =>
{
b.Property("xmin").ValueGeneratedOnAddOrUpdate()
.HasValueGenerator((_, __) => new TemporaryUIntValueGenerator());
});
actually returns the following error:
System.InvalidOperationException: The property 'xmin' on entity type 'IdentityRole<int>' has a temporary value while attempting to change the entity's state to 'Deleted'. Either set a permanent value explicitly or ensure that the database is configured to generate values for this property.
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState oldState, EntityState newState, Boolean acceptChanges)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState entityState, Boolean acceptChanges, Nullable`1 forceStateWhenUnknownKey)
at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.DiffData(TableMapping source, TableMapping target, DiffContext diffContext)
at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.Diff(TableMapping source, TableMapping target, DiffContext diffContext)+MoveNext()
at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.DiffCollection[T](IEnumerable`1 sources, IEnumerable`1 targets, DiffContext diffContext, Func`4 diff, Func`3 add, Func`3 remove, Func`4[] predicates)+MoveNext()
at System.Linq.Enumerable.ConcatIterator`1.MoveNext()
at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.Sort(IEnumerable`1 operations, DiffContext diffContext)
at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsModelDiffer.GetDifferences(IModel source, IModel target)
at Microsoft.EntityFrameworkCore.Migrations.Design.MigrationsScaffolder.ScaffoldMigration(String migrationName, String rootNamespace, String subNamespace, Stringlanguage)
at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_1.<.ctor>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
The property 'xmin' on entity type 'IdentityRole<int>' has a temporary value while attempting to change the entity's state to 'Deleted'. Either set a permanent value explicitly or ensure that the database is configured to generate values for this property.
mind you removing that config line and the single line of SeedData actually yields an empty migration, there's no staged change besides the seed data.
@NinoFloris I see, sorry that it's still not working. We'll try to fix the underlying issue in 2.2.2
This issue has been fixed on the EF Core side in https://github.com/aspnet/EntityFrameworkCore/issues/14161 and released in EF Core 2.2.2. I can confirm that it is now possible to seed entities which use xmin.
Be sure to explicitly take a dependency on EF Core 2.2.2 as the currently released version of the Npgsql provider is 2.2.0, which depends on EF Core 2.2.0 (I'll try to release a patch version for the Npgsql provider soon).
For clarity, the workaround using temporary values proposed above is not necessary and in fact won't work. Simply define xmin as the concurrency token (e.g. by calling ForNpgsqlUseXminAsConcurrencyToken() on the entity), don't define any value generator and everything should just work.
Most helpful comment
@NinoFloris I see, sorry that it's still not working. We'll try to fix the underlying issue in 2.2.2