EF AmbigiousMatchException虚拟int被Enum覆盖

时间:2018-11-14 15:39:32

标签: entity-framework

我对EF有一个有趣的问题。我所有的模型都继承自EntityBase

public abstract class EntityBase
{
    [Column(Order = 0)]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    [Key]
    public virtual int Id { get; set; }
}

Id是虚拟的,因为在某些模型上我需要覆盖属性。但是,我现在有一个需要枚举作为id的模型。

internal class Katalog : EntityBase
{
    [Key]
    [Column(Order = 0)]
    public new EKatalog Id { get { return (EKatalog)base.Id; } set { base.Id = (int)value; } }
    ////EKatalog IKatalog.Id => throw new System.NotImplementedException();

    ////public override int Id { get => base.Id; set => base.Id = value; }
}

在这个星座中,我从EF得到了AmbigiousMatchException(来自Type.GetProperty。如果发现多个,则抛出此异常)。

所以我试图在OnModelCreating中重新配置基本属性

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Types().Where(t => t == typeof(Katalog)).Configure(c =>
            {
                //var properties = c.ClrType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.Name == "Id");
                //PropertyInfo propIdKatalog = c.ClrType.GetProperty("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); // .Where(p => p.Name == "Id");
                //PropertyInfo propIdBase = c.ClrType.GetProperties(BindingFlags.Public | BindingFlags.Instance).First(p => p.Name == "Id" & p.DeclaringType == typeof(EntityBase));

                ////propIdBase.CustomAttributes.

                //ConventionPrimitivePropertyConfiguration propConfigBase = c.Property(propIdBase);
                //propConfigBase.HasColumnAnnotation("NotMapped", new NotMappedAttribute());

                //var propConfig = c.Property(propIdKatalog);

                //propConfig.HasColumnOrder(0);
                //propConfig.IsKey();
            });

        ////var converter = new ValueConverter<Katalog>();
        //modelBuilder.Entity<Katalog>().Ignore(x=>x.)

        ////modelBuilder.Entity<Katalog>().Map(m =>
        ////{
        ////    m.MapInheritedProperties().Property(x => x.Id).HasColumnAnnotation()
        //})
    }

我评论了我所有的想法,因为没有任何效果。我需要的是特别在这种类型,以不映射基本id列。在Katalog中,我需要枚举id属性。

编辑1: 检查答案后,我发现,问题发生在种子方法中。我有这个种子:

    protected override void Seed(EFOverwriteIntEnum.ApplicationContext.DatabaseContext context)
    {
        //  This method will be called after migrating to the latest version.

        //  You can use the DbSet<T>.AddOrUpdate() helper extension method 
        //  to avoid creating duplicate seed data.

        #region Katalogeinträge

        List<Katalog> katalogEntry = new List<Katalog>
        {
            new Katalog
            {
                Id = EKatalog.BeiratWert, Theme = "BeiratWert"
            },
            new Katalog
            {
                Id = EKatalog.BringungWert, Theme = "BringungWert"
            },
        };

        foreach (var entry in katalogEntry)
        {
            // context.Katalog.AddOrUpdate(entry); // AmbigiousMatchException - bug in DbSetMigrationsExtensions.AddOrUpdate
            context.Katalog.Add(entry);
            context.SaveChanges();
        }
        #endregion
    }

我使用了DbSetMigrationsExtensions中的AddOrUpdate-Method,如在生成的注释中建议的那样。但是特别是在这种情况下,存在一个错误。如果我使用普通的Add和SaveChanges-Method,它就可以工作。

感谢您的帮助。我会将给定的答案标记为答案,因为它为我指明了正确的方向。

Nico

1 个答案:

答案 0 :(得分:0)

我可以使它与EF6一起使用,但是不能与EF Core一起使用。

EF6:我使用了EntityTypeConfiguration。我想这里的关键是避免重复的[Key]声明。以下工作:

    public enum TestIds
    {
        None = 0,
        Sun,
        Moon,
        Earth
    }

   public abstract class BaseEntity
    {
        public int Id { get; set; }
    }

    public class TestEntity : BaseEntity
    {
        public new TestIds Id { get { return (TestIds)base.Id; } set { base.Id = (int)value; } }

        public string Name { get; set; }
    }

    public class TestEntityConfiguration : EntityTypeConfiguration<TestEntity>
    {
        public TestEntityConfiguration()
        {
            ToTable("TestEntity");
            HasKey(x => x.Id)
                .Property(x => x.Id)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
        }
    }

我可以使用枚举通过ID访问实体:

[Test]
public void TestByEnum()
{
    using (var context = new TestDbContext())
    {
        var entities = context.TestEntities.ToList();

        var earth = context.TestEntities.Single(x => x.Id == TestIds.Earth);

    }
}

EFCore不能这么说。使用IEntityTypeConfiguration不能停止抱怨类型不匹配。我在“ new”子类属性上尝试了[NotMapped],但随后似乎忽略了Key定义。

最终,这是不为该实体类型扩展基类的情况。基类用于具有 identical 属性和行为的类。一旦您需要偏离该实体,该实体就不再是该公共集合的一部分。通常,这是过早优化或保持一致性的迹象。 (我认为它是反模式的)将其构建为工作状态,然后在模式中进行优化以减少重复等。通常,它最终会获得比尝试最佳地编写代码更好的代码,然后在情况不佳时对其进行取消优化或修改适合。 :)