Scaffold-DbContext generates incorrect nav property on foreign key with filtered unique index
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 42/100
Research direction
Reproduce the issue from the supplied SQL Server schema and Scaffold-DbContext command, then inspect the generated Person and DbContext output. Trace how the filtered unique index is interpreted when configuring the PersonRole relationship. Done means the generated parent navigation is a collection while the index filter remains represented in the model configuration.
Written by the indexing model from the issue text.
Description
I've run into an issue using the Scaffold-DbContext command for the Package Manager Console in Visual Studio to reverse engineer a database on a SQL Server 2016 instance. It seems that command misinterprets one-to-many foreign key relationships as one-to-one when there is a filtered unique index on the foreign key column(s) in the child table. The navigation property on the entity type generated for the parent table should be a collection of child entities but it is instead scaffolded as a single child entity.
Steps to reproduce
Here's a contrived example that should help illustrate the issue:
Create the following table structure in an empty SQL Server (2016) database:
CREATE TABLE [dbo].[Person](
[PersonId] [varchar](10) NOT NULL,
CONSTRAINT [PK_Person] PRIMARY KEY CLUSTERED ([PersonId])
)
CREATE TABLE [dbo].[PersonRole](
[PersonRoleId] [int] IDENTITY(1,1) NOT NULL,
[PersonId] [varchar](10) NOT NULL,
[RoleId] [varchar](5) NOT NULL,
[IsActive] [bit] NOT NULL,
CONSTRAINT [PK_PersonRole] PRIMARY KEY CLUSTERED ([PersonRoleId]),
CONSTRAINT [FK_PersonRole_Person] FOREIGN KEY ([PersonId]) REFERENCES [dbo].[Person]([PersonId])
)
CREATE UNIQUE INDEX [IX_PersonRole_PersonId] ON [dbo].[PersonRole]([PersonId]) WHERE [IsActive] = 1
Then, create a new project in Visual Studio using the Console App (.NET Core) template. Ensure that the project targets netcoreapp2.0 then add the following NuGet packages to the .csproj file:
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.2" />
Next, run the Scaffold-DbContext command in the Package Manager Console to reverse engineer the database (modify connection string as needed):
Scaffold-DbContext "server=.;database=ScaffoldDbContextTest;Integrated Security=SSPI" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models
Expected Result:
The PersonRole navigation property on the Person class should be of type ICollection<PersonRole> since the index allows for an unlimited number of rows with the same PersonId to exist in the PersonRole table as long as no more than one of them satisfies the filter clause.
Actual Result:
The configuration code in the DbContext class appears to describe the index correctly (including the filter clause) but the entity relationship is configured as one-to-one...
modelBuilder.Entity<PersonRole>(entity =>
{
entity.HasIndex(e => e.PersonId)
.IsUnique()
.HasFilter("([IsActive]=(1))");
...
entity.HasOne(d => d.Person)
.WithOne(p => p.PersonRole)
.HasForeignKey<PersonRole>(d => d.PersonId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_PersonRole_Person");
});
...and the navigation property in the Person class is therefore not a collection, as if the filter doesn't exist:
public PersonRole PersonRole { get; set; }
Further technical details
EF Core version: 2.0.2
Database Provider: Microsoft.EntityFrameworkCore.SqlServer
Database Server: SQL Server 2016 13.0.4206.0
Operating system: Windows 10 Enterprise
IDE: Visual Studio 2017 15.6.2
.NET Core SDK: 2.1.101
.NET Core runtime: 2.0.6
- Dominant language
- C#
- Stars
- 14.8k
- Forks
- 3.4k
- Avg merge
- 2d 5h
- Merged PRs (30d)
- 134
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from dotnet/efcore
-
Difficulty 4/5 3-5 days Newbie friendliness 55/100
-
customer-reported
Difficulty 5/5 Over a week Newbie friendliness 38/100
-
area-cosmos area-vector-search
Difficulty 5/5 Over a week Newbie friendliness 25/100
-
area-cosmos
Difficulty 5/5 Over a week Newbie friendliness 25/100
-
area-tools needs-design
Difficulty 4/5 3-5 days Newbie friendliness 25/100
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
-
:watch: Not Triaged 11.0 fundamentals/subsvc
Difficulty 2/5 1-3 hours Newbie friendliness 92/100
dotnet/AspNetCore.Docs#37699 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
SubtitleEdit/subtitleedit#15108 · 1 comment ·
-
area/docs-content Bug pulumi/docs
Difficulty 1/5 1-3 hours Newbie friendliness 94/100
-
agentic-workflows untriaged
Difficulty 2/5 1-3 hours Newbie friendliness 76/100