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

Scaffolded database fails OnModelCreating when table has index with included columns snake_case named #23068

Closed
adopilot opened this issue Oct 21, 2020 · 4 comments

Comments

@adopilot
Copy link

DbContex created scaffolding from existing database fails on method OnModelCreating in runtime if in database has tables with indexed which using columns named snake_cased.

Here is steps.
In sql create table with index

USE [Test]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Table_test](
	[Id] [int] IDENTITY(1,1) NOT NULL,
	[col_int] [int] NULL,
	[col_date] [date] NULL,
	[col_float] [float] NULL,
 CONSTRAINT [PK_Table_test] PRIMARY KEY CLUSTERED 
(
	[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [IX_Test_Tune] ON [dbo].[Table_test]
(
	[col_int] ASC
)
INCLUDE ( 	[col_date],
	[col_float]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

Then in Visual studio in Pacgae Manager Console

Scaffold-DbContext "data source=.;initial catalog=Test;persist security info=True;user id=xx;password=xxx;" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Data\Test -f
This will generate DbContext.
App with this DbContext will build and run, but at first call to database OnModelCreating
e.g:
var test= await _testContext.TableTests.ToListAsync();
App will fall into exception
Include property 'TableTest.col_date' not found.

Investigating OnModelCreating I fund that these lines cause exception

entity.HasIndex(e => e.ColInt, "IX_Test_Tune") 
                    .IncludeProperties(new[] { "col_date", "col_float" });

My test table is scaffolded like this:

 modelBuilder.Entity<TableTest>(entity =>
            {
                entity.ToTable("Table_test");

                entity.HasIndex(e => e.ColInt, "IX_Test_Tune") 
                    .IncludeProperties(new[] { "col_date", "col_float" });//This part where is falling 

                entity.Property(e => e.ColDate)
                    .HasColumnType("date")
                    .HasColumnName("col_date");

                entity.Property(e => e.ColFloat).HasColumnName("col_float");

                entity.Property(e => e.ColInt).HasColumnName("col_int");
            });

Annoying thing is that this happening in runtime after app is started, and exception message is so unclear to find what is wrong.
If you have large set of index like this in db you have to run over and over to find all wrong indexes, and comment them.
If we could change the column names then we would not use the db-first approach

EF Core version: 5.0.0-rc.2.20475.6
Microsoft.EntityFrameworkCore.Tools :5.0.0-rc.2.20475.6
Target framework: .NET 5.0 RC2
Operating system: Windows 10 x64
SQL Server version: Microsoft SQL Server 2012 (SP3-GDR) (KB4019092) - 11.0.6251.0 (X64)
IDE: Visual Studio 2019 16.8.0 Preview 5.0

@ErikEJ
Copy link
Contributor

ErikEJ commented Oct 21, 2020

Have you tried -UseDatabaseNames option?

@adopilot
Copy link
Author

adopilot commented Oct 21, 2020

Thank you @ErikEJ scaffolding with UseDatabaseNames will make dbcontext that hasn't got a problem with indexes that include colons with snake_case names but using this option makes every entity and property have an ugly snake case name.

I already scaffolded the database with these indexes before .Net5 RC2.
Im not sure that this problem was caused by the newest version or because i downloaded your DBEF power tools.
I noticed that now names of the dbsets are in plural did EFcore changed convention again or did your plugin is mixed with Scaffold-DbContext command.

Here is spinet from my db context scaffolded before and after (.Net5 RC2 and power-eftools).
Before (working):

        modelBuilder.Entity<Berger>(entity =>
            {
                entity.ToTable("berger", "dbo");
                entity.HasIndex(e => new { e.Id, e.L, e.Mpc, e.P12, e.P6, e.Poslati, e.StatusS, e.ArtId, e.Diff, e.Dzu, e.GrpId })
                    .HasName("bergertUNEaDO");
                entity.Property(e => e.Id)
                    .HasColumnName("id")
                    .ValueGeneratedNever();
                entity.Property(e => e.ArtId).HasColumnName("artId");
                entity.Property(e => e.Diff).HasColumnName("diff");
                entity.Property(e => e.Dzu)
                    .HasColumnName("dzu")
                    .HasColumnType("datetime");
                entity.Property(e => e.GrpId).HasColumnName("grpId");
                entity.Property(e => e.L).HasColumnName("l");
                entity.Property(e => e.Mpc)
                    .HasColumnName("mpc")
                    .HasColumnType("money");
                entity.Property(e => e.P12).HasColumnName("p12");
                entity.Property(e => e.P6).HasColumnName("p6");
                entity.Property(e => e.Poslati).HasColumnName("poslati");
                entity.Property(e => e.StatusS)
                    .IsRequired()
                    .HasColumnName("statusS")
                    .HasMaxLength(8)
                    .IsUnicode(false);
                entity.HasOne(d => d.Art)
                    .WithMany(p => p.Berger)
                    .HasForeignKey(d => d.ArtId)
                    .OnDelete(DeleteBehavior.ClientSetNull)
                    .HasConstraintName("FK_berger_ART");
                entity.HasOne(d => d.Grp)
                    .WithMany(p => p.Berger)
                    .HasForeignKey(d => d.GrpId)
                    .OnDelete(DeleteBehavior.ClientSetNull)
                    .HasConstraintName("FK_berger_GRUPE_RJ1");
            });

After (faling):

modelBuilder.Entity<Berger>(entity =>
            {
                entity.ToTable("berger", "dbo");
                //Falling part
                entity.HasIndex(e => e.GrpId, "bergertUNEaDO")
                    .IncludeProperties(new[] { "id", "artId", "p12", "p6", "dzu", "l", "mpc", "statusS", "diff", "poslati" });
                entity.Property(e => e.Id)
                    .ValueGeneratedNever()
                    .HasColumnName("id");
                entity.Property(e => e.ArtId).HasColumnName("artId");
                entity.Property(e => e.Diff).HasColumnName("diff");
                entity.Property(e => e.Dzu)
                    .HasColumnType("datetime")
                    .HasColumnName("dzu");
                entity.Property(e => e.GrpId).HasColumnName("grpId");
                entity.Property(e => e.L).HasColumnName("l");
                entity.Property(e => e.Mpc)
                    .HasColumnType("money")
                    .HasColumnName("mpc");
                entity.Property(e => e.P12).HasColumnName("p12");
                entity.Property(e => e.P6).HasColumnName("p6");
                entity.Property(e => e.Poslati).HasColumnName("poslati");
                entity.Property(e => e.StatusS)
                    .IsRequired()
                    .HasMaxLength(8)
                    .IsUnicode(false)
                    .HasColumnName("statusS");
                entity.HasOne(d => d.Art)
                    .WithMany(p => p.Bergers)
                    .HasForeignKey(d => d.ArtId)
                    .OnDelete(DeleteBehavior.ClientSetNull)
                    .HasConstraintName("FK_berger_ART");
                entity.HasOne(d => d.Grp)
                    .WithMany(p => p.Bergers)
                    .HasForeignKey(d => d.GrpId)
                    .OnDelete(DeleteBehavior.ClientSetNull)
                    .HasConstraintName("FK_berger_GRUPE_RJ1");
            });

                                                                                             Thank you 

@ajcvickers
Copy link
Member

Duplicate of #22150

@ajcvickers ajcvickers marked this as a duplicate of #22150 Oct 21, 2020
@ErikEJ
Copy link
Contributor

ErikEJ commented Oct 22, 2020

@adopilot pluralization is enabled by default with EF Core 5 (breaking change)

You can disable with the -NoPluralize option

@ajcvickers ajcvickers reopened this Oct 16, 2022
@ajcvickers ajcvickers closed this as not planned Won't fix, can't repro, duplicate, stale Oct 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants