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.78k stars 3.19k forks source link

6.0.0-rc.1.21452.10: Navigations can only target entity types with keys #26073

Closed yuryjhol closed 3 years ago

yuryjhol commented 3 years ago

dotnet --version 6.0.100-rc.1.21458.32

dotnet ef --version Entity Framework Core .NET Command-line Tools 6.0.0-rc.1.21452.10

dotnet new console -o EFGetStarted cd EFGetStarted

dotnet add package -v 6.0.0-rc.1.21452.10 Microsoft.EntityFrameworkCore.SqlServer dotnet add package -v 6.0.0-rc.1.21452.10 Microsoft.EntityFrameworkCore.Design

dotnet ef dbcontext scaffold "Server=localhost;Database=pubs;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer

Program.cs: var pubsContext = new EFGetStarted.pubsContext(); var count = pubsContext.Discounts.Count();

dotnet run Unhandled exception. System.InvalidOperationException: The navigation '' cannot be added because it targets the keyless entity type 'Discount'. Navigations can only target entity types with keys. at Microsoft.EntityFrameworkCore.Metadata.Internal.ForeignKey.Navigation(Nullable1 propertyIdentity, ConfigurationSource configurationSource, Boolean pointsToPrincipal) at Microsoft.EntityFrameworkCore.Metadata.Internal.ForeignKey.SetPrincipalToDependent(String name, ConfigurationSource configurationSource) at Microsoft.EntityFrameworkCore.Metadata.Internal.InternalForeignKeyBuilder.HasNavigations(Nullable1 navigationToPrincipal, Nullable1 navigationToDependent, EntityType principalEntityType, EntityType dependentEntityType, ConfigurationSource configurationSource) at Microsoft.EntityFrameworkCore.Metadata.Internal.InternalForeignKeyBuilder.HasNavigations(String navigationToPrincipalName, String navigationToDependentName, EntityType principalEntityType, EntityType dependentEntityType, ConfigurationSource configurationSource) at Microsoft.EntityFrameworkCore.Metadata.Builders.ReferenceNavigationBuilder.WithManyBuilder(MemberIdentity collection) at Microsoft.EntityFrameworkCore.Metadata.Builders.ReferenceNavigationBuilder.WithManyBuilder(String navigationName) at Microsoft.EntityFrameworkCore.Metadata.Builders.ReferenceNavigationBuilder2.WithMany(String navigationName) at EFGetStarted.pubsContext.<>c.b51_1(EntityTypeBuilder1 entity) in C:\Projects\VS2022\EFGetStarted\pubsContext.cs:line 124 at Microsoft.EntityFrameworkCore.ModelBuilder.Entity[TEntity](Action1 buildAction) at EFGetStarted.pubsContext.OnModelCreating(ModelBuilder modelBuilder) in C:\Projects\VS2022\EFGetStarted\pubsContext.cs:line 99 at Microsoft.EntityFrameworkCore.Infrastructure.ModelCustomizer.Customize(ModelBuilder modelBuilder, DbContext context) at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder, ModelDependencies modelDependencies) at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, ModelCreationDependencies modelCreationDependencies, Boolean designTime) at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel(Boolean designTime) at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model() at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.b7_3(IServiceProvider p) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSite(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSite(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSite(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSite(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSite(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSite(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass2_0.b__0(ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceProvider.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_ContextServices() at Microsoft.EntityFrameworkCore.DbContext.get_Model() at Microsoft.EntityFrameworkCore.Internal.InternalDbSet1.get_EntityType() at Microsoft.EntityFrameworkCore.Internal.InternalDbSet1.CheckState() at Microsoft.EntityFrameworkCore.Internal.InternalDbSet1.get_EntityQueryable() at Microsoft.EntityFrameworkCore.Internal.InternalDbSet1.System.Linq.IQueryable.get_Provider() at System.Linq.Queryable.Count[TSource](IQueryable`1 source) at Program.

$(String[] args) in C:\Projects\VS2022\EFGetStarted\Program.cs:line 2

ajcvickers commented 3 years ago

@yuryjhol Please post a database schema (preferably simplified) that results in this behavior after it has been scaffolded to a DbContext.

ErikEJ commented 3 years ago

@ajcvickers I am able to repro on 6 RC1 with this schema:

(Or just the two tables below)

https://raw.githubusercontent.com/microsoft/sql-server-samples/master/samples/databases/northwind-pubs/instpubs.sql

Also tested on 5.0.9, no errors.

This is where the errors occurs (call to HasOne()):


            entity.HasNoKey();

            entity.ToTable("discounts");

            entity.HasOne(d => d.Stor)
                .WithMany()
                .HasForeignKey(d => d.StorId)
                .HasConstraintName("FK__discounts__stor___3C69FB99");

Schema of discounts:

CREATE TABLE [dbo].[discounts](
    [discounttype] [varchar](40) NOT NULL,
    [stor_id] [char](4) NULL,
    [lowqty] [smallint] NULL,
    [highqty] [smallint] NULL,
    [discount] [decimal](4, 2) NOT NULL
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[discounts]  WITH CHECK ADD FOREIGN KEY([stor_id])
REFERENCES [dbo].[stores] ([stor_id])
GO

Schema of stores:

CREATE TABLE [dbo].[stores](
    [stor_id] [char](4) NOT NULL,
    [stor_name] [varchar](40) NULL,
    [stor_address] [varchar](40) NULL,
    [city] [varchar](20) NULL,
    [state] [char](2) NULL,
    [zip] [char](5) NULL,
 CONSTRAINT [UPK_storeid] PRIMARY KEY CLUSTERED 
(
    [stor_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
smitpatel commented 3 years ago

Minimal repro


    public class Store
    {
        public int StoreId { get; set; }
    }

    public class Discount
    {
        public string DiscountType { get; set; }
        public int? StoreId { get; set; }
        public Store Store { get; set; }
    }

modelBuilder.Entity<Discount>(b =>
            {
                b.HasNoKey();

                b.HasOne(e => e.Store).WithMany();
            });

Check in WithMany is incorrect and ends up throwing. Without WithMany call it works fine.

This is regression from 5.0

cc: @ajcvickers @AndriySvyryd

AndriySvyryd commented 3 years ago

@smitpatel Are you going to fix it? Take a look at https://github.com/dotnet/efcore/issues/24283 also

smitpatel commented 3 years ago

Yes, fixing this. Also "poached" #24283

ZvonimirMatic commented 3 years ago

Is this fix going to be available in RC2?

AndriySvyryd commented 3 years ago

@ZvonimirMatic No, you'll need to wait until 6.0.0 (GA) or use a daily build.