EF Core, Invalid column name exception after update from netcore2.2 to netcore3.1

ef-core-3.1 entity-framework entity-framework-core

Question

Since I've updated from .netcore2.2 to .netcore3.1, I'm facing new weird exception "Invalid column name 'TenantTemplateTypeID1'". Please not the '1', that shouldn't be here. There is NO TenantTemplateTypeID1 anywhere in the code, so I assume it's generated by EF core.

EF core version: 3.1.1

Exception:

Exception: Invalid column name 'TenantTemplateTypeID1'.
Invalid column name 'TenantTemplateTypeID1'.
Invalid column name 'TenantTemplateTypeID1'.
Invalid column name 'TenantTemplateTypeID1'.
StactTrace:    at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at Microsoft.Data.SqlClient.SqlDataReader.TryConsumeMetaData()
   at Microsoft.Data.SqlClient.SqlDataReader.get_MetaData()

Query:

var t = engineCtx.TenantTemplates
                 .AsNoTracking()
                 .Include(tt => tt.TenantTemplateParameters)
                 .Include(tt => tt.TenantTemplateStyles)
                 .FirstOrDefault(tt => tt.TenantTemplateTypeID == tenantTemplateTypeID);

DbContext

modelBuilder.Entity<Db.Model.TenantTemplate>(entity =>
            {
                entity.HasKey(e => e.TenantTemplateTypeID)
                      .HasName("PK_TenantTemplate_TenantTemplateTypeID");

                entity.ToTable("TenantTemplates", "templateEngine");

                entity.Property(e => e.TenantTemplateTypeID)
                      .HasColumnName("TenantTemplateTypeId");
                //... not related rows removed
                entity.HasMany(e => e.TenantTemplateParameters)
                      .WithOne(e => e.TenantTemplate)
                      .HasConstraintName("FK_TenantTemplate_TenantTemplateParameters")
                      .OnDelete(DeleteBehavior.Restrict);

                entity.HasMany(e => e.TenantTemplateStyles)
                      .WithOne(e => e.TenantTemplate)
                      .HasConstraintName("FK_TenantTemplate_TenantTemplateStyles")
                      .OnDelete(DeleteBehavior.Restrict);
            });

DB model contains only properties without any attributes.

public partial class TenantTemplate
    {
         public long TenantTemplateTypeID { get; set; }
         // not related rows removed
         public virtual ICollection<TenantTemplateParameter> TenantTemplateParameters { get; set; }
         public virtual ICollection<TenantTemplateStyle> TenantTemplateStyles { get; set; }
    }
// TenantTemplateStyle is exacly the same (just PK has a different name)
public class TenantTemplateParameter
   {
        public long TenantTemplateParameterID { get; set; }
        public long TenantTemplateTypeID { get; set; }
        // rows removed
        public virtual TenantTemplate TenantTemplate { get; set; }
   }

Anyone knows some overround? Thanks...

1
1
2/4/2020 7:08:09 AM

Accepted Answer

I'm pretty sure this is caused by the following EF Core 3.0 breaking change - The foreign key property convention no longer matches same name as the principal property.

According to that rule, TenantTemplateTypeID in TenantTemplateParameter is not considered as FK name.

The weird thing is that at the same time it is the default conventional FK name according to the rules explained in Foreign key shadow properties:

The property will be named <navigation property name><principal key property name> (the navigation on the dependent entity, which points to the principal entity, is used for the naming). If the principal key property name includes the name of the navigation property, then the name will just be <principal key property name>. If there is no navigation property on the dependent entity, then the principal type name is used in its place.

Since the name is already reserved by the "non FK" property, conventional name builder adds index to the default conventional name, hence the observed behavior.

I would consider this as bug/defect of the current EF Core implementation. The workaround/solution of course is to explicitly map the FK property, e.g.

entity.HasMany(e => e.TenantTemplateParameters)
      .WithOne(e => e.TenantTemplate)
      .HasForeignKey(e => e.TenantTemplateTypeID) // <--
      .HasConstraintName("FK_TenantTemplate_TenantTemplateParameters")
      .OnDelete(DeleteBehavior.Restrict);

and similar for the other relationship (with TenantTemplateStyle) if it's using the same naming convention.

2
2/4/2020 7:55:40 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow