isukces / EfCore.Shaman

Fix some EntityFrameworkCore flaws.
MIT License
22 stars 8 forks source link

ArgumentException in FixMigrationUp #21

Open Systemdir opened 6 years ago

Systemdir commented 6 years ago
  var colsDic = entity
  .Properites
  .Where(info => !info.IsNotMapped && !info.IsNavigationProperty)
  .ToDictionary(a => a.ColumnName, StringComparer.OrdinalIgnoreCase);

FixMigrationUp throws an Argument Exception "An item with the same key has already been added." in ModelFixer.cs#L173 when when a deriving class specifies the same property. This is due to entity containing the same property multiple times. In my case I had a class with an int Id which derived from IdentityRole also specifying an int Id property.

As a quick fix to this issue I added ...

ColumnInfo duplicateEntry = dbSetInfo.Properites.FirstOrDefault(ci => ci.ColumnName == columnInfo.ColumnName);
if (duplicateEntry != null)
{
    var getMethod = propertyInfo.GetGetMethod(false);
    if (getMethod.GetBaseDefinition() != getMethod)
    {
        // overrides the base property
        // => remove base property and add the deriving property
        dbSetInfo.Properites.Remove(duplicateEntry);
        dbSetInfo.Properites.Add(columnInfo);
    }
    continue;
}

... into CreateDbSetWrapper.cs just before dbSetInfo.Properites.Add(columnInfo);

isukces commented 6 years ago

How Id properties from base and derived class are mapped into table columns? Have you put any annotations?

Systemdir commented 6 years ago

The base class extends from IdentityRole. This is how it is defined by Microsofts IdentityDbContext:

   builder.Entity<TRole>((Action<EntityTypeBuilder<TRole>>) (b =>
   {
    b.HasKey((Expression<Func<TRole, object>>) (r => (object) r.Id));
    b.HasIndex((Expression<Func<TRole, object>>) (r => r.NormalizedName)).HasName("RoleNameIndex").IsUnique(true);
    b.ToTable<TRole>("AspNetRoles");
    b.Property<string>((Expression<Func<TRole, string>>) (r => r.ConcurrencyStamp)).IsConcurrencyToken(true);
    b.Property<string>((Expression<Func<TRole, string>>) (u => u.Name)).HasMaxLength(256);
    b.Property<string>((Expression<Func<TRole, string>>) (u => u.NormalizedName)).HasMaxLength(256);
    b.HasMany<TUserRole>((Expression<Func<TRole, IEnumerable<TUserRole>>>) null).WithOne((string) null).HasForeignKey((Expression<Func<TUserRole, object>>) (ur => (object) ur.RoleId)).IsRequired(true);
    b.HasMany<TRoleClaim>((Expression<Func<TRole, IEnumerable<TRoleClaim>>>) null).WithOne((string) null).HasForeignKey((Expression<Func<TRoleClaim, object>>) (rc => (object) rc.RoleId)).IsRequired(true);
  }));

The Id in the derived class had the [Key] attribute.