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

HasColumnName works incorrectly with inheritance #23031

Closed
impworks opened this issue Oct 17, 2020 · 3 comments
Closed

HasColumnName works incorrectly with inheritance #23031

impworks opened this issue Oct 17, 2020 · 3 comments

Comments

@impworks
Copy link

impworks commented Oct 17, 2020

Using HasColumnName with class inheritance works incorrectly: instead of configuring the value for current type, each config overwrites the column name for the entire inheritance tree.

Consider the following model classes:

public class Account
{
    public int Id {get; set;}
    public string Email {get; set;}
}

public class UserAccount: Account
{
    public string Group {get; set;}
}

public class AdminAccount: Account
{
}

And the following configuration:

public class AccountConfig : IEntityTypeConfiguration<Account>
{
    public void Configure(EntityTypeBuilder<Account> builder)
    {
        builder.Property(x => x.Id).ValueGeneratedOnAdd();
        builder.Property(x => x.Email).IsRequired();
        builder.ToTable("Account");
    }
}

public class UserAccountConfig : IEntityTypeConfiguration<UserAccount>
{
    public void Configure(EntityTypeBuilder<UserAccount> builder)
    {
        builder.Property(x => x.Id).HasColumnName("AccountId");
        builder.ToTable("UserAccount");
    }
}

public class AdminAccountConfig : IEntityTypeConfiguration<AdminAccount>
{
    public void Configure(EntityTypeBuilder<AdminAccount> builder)
    {
        builder.Property(x => x.Id).HasColumnName("AccountId");
        builder.ToTable("AdminAccount");
    }
}

Querying code is simple:

var account = await db.Accounts.FirstOrDefaultAsync(x => x.Email == "foo@example.com");

So this is the generated query:

exec sp_executesql N'SELECT [t].[AccountId], [t].[Email], [t].[Discriminator]
FROM (
    SELECT TOP(1) [a].[AccountId], [a].[Email], CASE
        WHEN [a0].[AccountId] IS NOT NULL THEN N''AdminAccount''
        WHEN [u].[AccountId] IS NOT NULL THEN N''UserAccount''
    END AS [Discriminator]
    FROM [dbo].[Account] AS [a]
    LEFT JOIN [dbo].[AdminAccount] AS [a0] ON [a].[AccountId] = [a0].[AccountId]
    LEFT JOIN [dbo].[UserAccount] AS [u] ON [a].[AccountId] = [u].[AccountId]
    WHERE [a].[Email] = @__email_0
) AS [t]
ORDER BY [t].[AccountId]',N'@__email_0 nvarchar(100)',@__email_0=N'foo@example.com'

The LEFT JOIN clauses are incorrect: the correct field name in Account table is [a].[Id], not [a].[AccountId].

While trying to investigate, I tried to use incorrect, but unique column names (UserAccount.AccountId1 and AdminAccount.AccountId2). This is the request I got:

exec sp_executesql N'SELECT [t].[AccountId2], [t].[Email], [t].[Discriminator]
FROM (
    SELECT TOP(1) [a].[AccountId2], [a].[Email], CASE
        WHEN [a0].[AccountId2] IS NOT NULL THEN N''AdminAccount''
        WHEN [u].[AccountId2] IS NOT NULL THEN N''UserAccount''
    END AS [Discriminator]
    FROM [dbo].[Account] AS [a]
    LEFT JOIN [dbo].[AdminAccount] AS [a0] ON [a].[AccountId2] = [a0].[AccountId2]
    LEFT JOIN [dbo].[UserAccount] AS [u] ON [a].[AccountId2] = [u].[AccountId2]
    WHERE [a].[Email] = @__email_0
) AS [t]
ORDER BY [t].[AccountId2]',N'@__email_0 nvarchar(100)',@__email_0=N'foo@example.com'

Notice how every single reference to the key property is now referred to as AccountId2, even when it should be Id in the base table and AccountId1 in UserAccount.

EF Core version: 5.0.0-rc.2.20475.6
Database provider: Microsoft.EntityFrameworkCore.SqlServer 5.0.0-rc.2.20475.6
Target framework: .NET Core 3.1
Operating system: Windows 10
IDE: Visual Studio 2019 16.4.3

@ajcvickers
Copy link
Member

Duplicate of #19811

@ajcvickers ajcvickers marked this as a duplicate of #19811 Oct 19, 2020
@impworks
Copy link
Author

@ajcvickers I came across this bug in actual production code when porting it from EF6 to EF Core. Is it possible to at least display a comprehensible configuration error until the feature is properly implemented?

@AndriySvyryd
Copy link
Member

@impworks Due to the way the API is architected we can't detect on which entity type you started the configuration by the time HasColumnName is called. And changing this would be a major breaking change as it would involve changing the return type of Property

@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