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

Setting entity/property name via IEntityTypeAddedConvention breaks migration #35330

Open
grosch-intl opened this issue Dec 13, 2024 · 3 comments

Comments

@grosch-intl
Copy link

Ask a question

When I run an initial migration, everything works without issue, and the many-to-many table relationship you auto-generated below appears in the migration. However, if I try to use an IEntityTypeAddedConvention to make things snake case, the migration aborts.

Include your code

internal partial class RandomEntityTypeConvention : IEntityTypeAddedConvention
{
    private static readonly Regex UpperCaseRegex = AutoGeneratedRegex();

    [GeneratedRegex("([a-z0-9])([A-Z])", RegexOptions.Compiled | RegexOptions.ExplicitCapture, matchTimeoutMilliseconds: 1000)]
    private static partial Regex AutoGeneratedRegex();

    private static string ToSnakeCase(string name) => UpperCaseRegex.Replace(name, "$1_$2").ToLowerInvariant();

    #region IEntityTypeAddedConvention implementation
    public void ProcessEntityTypeAdded(IConventionEntityTypeBuilder entityTypeBuilder, IConventionContext<IConventionEntityTypeBuilder> context) {
        var entityType = entityTypeBuilder.Metadata;

        var name = entityType.ClrType.Name;
        entityType.SetTableName(ToSnakeCase(name));

        foreach (var property in entityType.GetProperties())
            property.SetColumnName(ToSnakeCase(property.Name));
    }
    #endregion
}

Failure message from migration

Unable to create a 'DbContext' of type 'SdcDatabaseContext'. The exception 'Cannot use table 'dictionary2' for entity type 'ExportControlClassificationNumberSoftwarePackage (Dictionary<string, object>)' since it is being used for entity type 'DistributionFileSoftwarePackage (Dictionary<string, object>)' and potentially other entity types, but there is no linking relationship. Add a foreign key to 'ExportControlClassificationNumberSoftwarePackage (Dictionary<string, object>)' on the primary key properties and pointing to the primary key on another entity type mapped to 'dictionary2'.' was thrown while attempting to create an instance. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728

Good code you generate if I don't add the convention

migrationBuilder.CreateTable(
    name: "ExportControlClassificationNumberSoftwarePackage",
    columns: table => new
    {
        ExportControlClassificationNumbersId = table.Column<int>(type: "integer", nullable: false),
        SoftwarePackagesId = table.Column<int>(type: "integer", nullable: false)
    },
    constraints: table =>
    {
        table.PrimaryKey("PK_ExportControlClassificationNumberSoftwarePackage", x => new { x.ExportControlClassificationNumbersId, x.SoftwarePackagesId });
        table.ForeignKey(
            name: "FK_ExportControlClassificationNumberSoftwarePackage_ExportCont~",
            column: x => x.ExportControlClassificationNumbersId,
            principalTable: "ExportControlClassificationNumber",
            principalColumn: "Id",
            onDelete: ReferentialAction.Cascade);
        table.ForeignKey(
            name: "FK_ExportControlClassificationNumberSoftwarePackage_SoftwarePa~",
            column: x => x.SoftwarePackagesId,
            principalTable: "SoftwarePackage",
            principalColumn: "Id",
            onDelete: ReferentialAction.Cascade);
    });

Include provider and version information

EF Core version: 9.0.0
Database provider: Npgsql.EntityFrameworkCore.PostgreSQL 9.0.1
Target framework: .NET 9
Operating system: Windows 11
IDE: Visual Studio 2022 17.12.3

@grosch-intl
Copy link
Author

If I instead do this via OnModelCreating by looping through modelBuilder.Model.GetEntityTypes() then it doesn't fail.

@roji
Copy link
Member

roji commented Dec 14, 2024

This issue is lacking enough information for us to be able to fully understand what is happening. Please attach a small, runnable project or post a small, runnable code listing that reproduces what you are seeing so that we can investigate.

@grosch-intl
Copy link
Author

I tracked this down. In my posted convention code, where I call SetTableName is the issue. It appears that for the many-to-many tables that EF will automatically generate for me, the name is always passed to me as Dictionary`2. So I have to change that bit of code to this:

if (name is not "Dictionary`2")
    entityType.SetTableName(ToSnakeCase(name));

While that solves my issue, I'm wondering if there's a better way to handle this, as that feels fragile as I'm depending on some internal convention you're using that could change.

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