Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Scaffold-DbContext does not generate correct model for FKs that reference unique constraint column in parent table #11936

Closed
cbrianball opened this issue May 8, 2018 · 2 comments
Assignees
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Milestone

Comments

@cbrianball
Copy link

cbrianball commented May 8, 2018

Due to a bug that was well-document in the issues (thank you!). I have recently upgraded to EFCore 2.0+.

The upgrade process was fairly painless, but when I went to regenerate my context with Scaffold-DbContext, I got the following warning:

Could not scaffold the foreign key 'dbo.Child(KeyId)'. A key for 'Key' was not found in the principal entity type 'Parent'.

The navigation property between the two entities was also lost.

Here's my simplified schema:

Parent{
Id //Primary Key
Key //Unique constraint
}

Child{
KeyId //Primary Key, Foreign Key -> Parent(Key)
}

The Child table is NOT pointing to the PK of the Parent table, but instead, another column that has a unique constraint. This worked fine under EF Core 1+, but the scaffolding tool doesn't seem to work correctly for EF Core 2+.

If I manually add the navigation properties to the entities and manually update the context to configure the model, everything works fine, so this appears to be a problem with the scaffolding tool (or some change in the conventions between EF Core 1 and EF Core 2 that the scaffolding tool uses).

Further technical details

EF Core version: 2.0.3
Database Provider: Microsoft.EntityFrameworkCore.SqlServer
Operating system: Windows 10
IDE: Visual Studio 2017 15.6.6

@smitpatel
Copy link
Member

I tried to reproduce above using Entity Framework Core 2.2.0-preview2-35157 (latest package on NuGet) but the FK is scaffolded correctly for me.
Database schema

      CREATE TABLE [Parent] (
          [Id] int NOT NULL IDENTITY,
          [Key] int NOT NULL,
          CONSTRAINT [PK_Parent] PRIMARY KEY ([Id]),
          CONSTRAINT [AK_Parent_Key] UNIQUE ([Key])
      );
      CREATE TABLE [Child] (
          [KeyId] int NOT NULL,
          CONSTRAINT [PK_Child] PRIMARY KEY ([KeyId]),
          CONSTRAINT [FK_Child_Parent_KeyId] FOREIGN KEY ([KeyId]) REFERENCES [Parent] ([Key]) ON DELETE CASCADE
      );

Generated model

    public partial class Parent
    {
        public int Id { get; set; }
        public int Key { get; set; }

        public virtual Child Child { get; set; }
    }
    public partial class Child
    {
        public int KeyId { get; set; }

        public virtual Parent Key { get; set; }
    }

    public partial class _ModelAppContext : DbContext
    {
        public _ModelAppContext()
        {
        }

        public _ModelAppContext(DbContextOptions<_ModelAppContext> options)
            : base(options)
        {
        }

        public virtual DbSet<Child> Child { get; set; }
        public virtual DbSet<Parent> Parent { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.
                optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=_ModelApp;Trusted_Connection=True;Connect Timeout=5;ConnectRetryCount=0");
            }
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Child>(entity =>
            {
                entity.HasKey(e => e.KeyId);

                entity.Property(e => e.KeyId).ValueGeneratedNever();

                entity.HasOne(d => d.Key)
                    .WithOne(p => p.Child)
                    .HasPrincipalKey<Parent>(p => p.Key)
                    .HasForeignKey<Child>(d => d.KeyId);
            });

            modelBuilder.Entity<Parent>(entity =>
            {
                entity.HasIndex(e => e.Key)
                    .HasName("AK_Parent_Key")
                    .IsUnique();
            });
        }
    }

Since original issue was reported for 2.0.3, it is likely to be fixed already.
If you are able to reproduce the issue in latest version then please provide SQL to generate database.

@smitpatel smitpatel added closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. and removed size~1-day labels Oct 3, 2018
@smitpatel smitpatel removed this from the 2.2.0 milestone Oct 3, 2018
smitpatel added a commit that referenced this issue Oct 3, 2018
Regression test for #11936
It is already working in latest package
@smitpatel smitpatel reopened this Oct 3, 2018
smitpatel added a commit that referenced this issue Oct 4, 2018
Regression test for #11936
It is already working in latest package
@smitpatel
Copy link
Member

@ajcvickers to assign milestone.

@ajcvickers ajcvickers added this to the 2.2.0 milestone Oct 5, 2018
@ajcvickers ajcvickers modified the milestones: 2.2.0-preview3, 2.2.0 Nov 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Projects
None yet
Development

No branches or pull requests

4 participants