dotnet / efcore

EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
https://docs.microsoft.com/ef/
MIT License
13.71k stars 3.17k forks source link

DbContext: Identity value generation cannot be used because the property type is byte #7161

Closed cjcfreitas closed 7 years ago

cjcfreitas commented 7 years ago

Steps to reproduce

Trying to create a table where primary key is of type tinyint and is identity. Tried with anotations [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] and fluent API UseSqlServerIdentityColumn()

The issue

I get this error: Identity value generation cannot be used for the property 'Id' on entity type 'Cargo' because the property type is 'byte'. Identity value generation can only be used with signed integer properties.

Exception message:
Stack trace:
Project DFWeb (.NETCoreApp,Version=v1.1) was previously compiled. Skipping compilation.
dotnet : System.ArgumentException: Identity value generation cannot be used for the property 'Id' on entity type 'Cargo' because the property type is 
'byte'. Identity value generation can only be used with signed integer properties.
At line:1 char:1
+ dotnet ef migrations add "Inicial"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (System.Argument...ger properties.:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

   at Microsoft.EntityFrameworkCore.Metadata.SqlServerPropertyAnnotations.SetValueGenerationStrategy(Nullable`1 value)

   at Microsoft.EntityFrameworkCore.Metadata.Internal.SqlServerPropertyBuilderAnnotations.ValueGenerationStrategy(Nullable`1 value)

   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.SqlServerValueGenerationStrategyConvention.Apply(InternalPropertyBuilder propertyBuilder, 
DatabaseGeneratedAttribute attribute, MemberInfo clrMember)

   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.PropertyAttributeConvention`1.Apply(InternalPropertyBuilder propertyBuilder)

   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnPropertyAdded(InternalPropertyBuilder propertyBuilder)

   at Microsoft.EntityFrameworkCore.Metadata.Internal.EntityType.AddProperty(String name, Type propertyType, MemberInfo memberInfo, ConfigurationSource 
configurationSource, Boolean runConventions)

   at Microsoft.EntityFrameworkCore.Metadata.Internal.EntityType.AddProperty(MemberInfo memberInfo, ConfigurationSource configurationSource, Boolean 
runConventions)

   at Microsoft.EntityFrameworkCore.Metadata.Internal.InternalEntityTypeBuilder.Property(Property existingProperty, String propertyName, Type propertyType, 
MemberInfo clrProperty, Nullable`1 configurationSource)

   at Microsoft.EntityFrameworkCore.Metadata.Internal.InternalEntityTypeBuilder.Property(String propertyName, Type propertyType, MemberInfo clrProperty, 
Nullable`1 configurationSource)

   at Microsoft.EntityFrameworkCore.Metadata.Internal.InternalEntityTypeBuilder.Property(MemberInfo clrProperty, ConfigurationSource configurationSource)

   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.PropertyDiscoveryConvention.Apply(InternalEntityTypeBuilder entityTypeBuilder)

   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnEntityTypeAdded(InternalEntityTypeBuilder entityTypeBuilder)

   at Microsoft.EntityFrameworkCore.Metadata.Internal.Model.AddEntityType(EntityType entityType, Boolean runConventions)

   at Microsoft.EntityFrameworkCore.Metadata.Internal.InternalModelBuilder.Entity(Type type, ConfigurationSource configurationSource, Boolean runConventions)

   at Microsoft.EntityFrameworkCore.ModelBuilder.Entity(Type type)

   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.FindSets(ModelBuilder modelBuilder, DbContext context)

   at Microsoft.EntityFrameworkCore.Infrastructure.Internal.RelationalModelSource.FindSets(ModelBuilder modelBuilder, DbContext context)

   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder, IModelValidator 
validator)

   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)

   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel()

   at Microsoft.EntityFrameworkCore.Internal.LazyRef`1.get_Value()

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProvider provider)

   at Microsoft.Extensions.DependencyInjection.ServiceProvider.<>c__DisplayClass16_0.<RealizeService>b__0(ServiceProvider provider)

   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitTransient(TransientCallSite transientCallSite, ServiceProvider 
provider)

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, 
ServiceProvider provider)

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitTransient(TransientCallSite transientCallSite, ServiceProvider 
provider)

   at Microsoft.Extensions.DependencyInjection.ServiceProvider.<>c__DisplayClass16_0.<RealizeService>b__0(ServiceProvider provider)

   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)

   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)

   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)

Identity value generation cannot be used for the property 'Id' on entity type 'Cargo' because the property type is 'byte'. Identity value generation can only be used with signed integer properties.

Further technical details

SQL server does allow tinyint to be used with IDENTITY. As a workaround I used this: [Key, Column(TypeName = "tinyint IDENTITY(1,1)")]

EF Core version: 1.1 Operating system: Windows 10 Visual Studio version: VS2015 Community

Best regards.

ajcvickers commented 7 years ago

@cjcfreitas Could you explain a little about why you need this? Why is it that you need a tinyint column for this rather than something slightly larger? Are you sure that the number of rows won't exceed the value space?

Note for triage: The problem with allowing this is that there is a a high chance of overlap between temporary values and real values. Temporary values start at 255 and count down. Real values start at 1 and count up.

cjcfreitas commented 7 years ago

@ajcvickers One can always use a larger format. I use tinyint as PK in small master tables (e.g. document types, wharehouses, VAT taxes) when I am sure there will be only a few items. This will be FK in larger tables. I know there are different opinions about this, but I usually favor using the most restrictive data-type available whenever I am sure it wont overflow (Hard disk space is cheap but it's not the only issue).

rowanmiller commented 7 years ago

We think we should make this a warning (with a default behavior of warn rather than throw). Any pushback @ajcvickers?

ajcvickers commented 7 years ago

Sounds good.

spyofborg commented 4 years ago

Just wondering, but does EF Core hates tinyint? Tinyint is something that should be used if you know you never need more than 255. For example, in my table I use tinybit on EmployeeRoles, that means, is a standard employee, Team leader, and Manager, that is it, why would I use smallint or int in this case? EF Core should accept that DBs do use tinyint. :)

roji commented 4 years ago

FWIW using auto-increment value generation for a type as small and constrained as tinyint sounds like asking for trouble... tinyint definitely makes sense when you have a closed set of known values which will never exceed 255, but if you're using value generation that already means you're not quite sure how many you're going to have...

ErikEJ commented 4 years ago

@spyofborg in other words, just use tinyint and assign the key values yourself