EF AmbigiousMatchException виртуальный int перезаписывается с помощью Enum - PullRequest
0 голосов
/ 14 ноября 2018

У меня есть интересная проблема с 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; }
}

В этом созвездии я получаю AmbigiousMatchException от EF (это происходит из 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()
        //})
    }

Я прокомментировал все свои идеи, потому что на самом деле ничего не работает. Что мне нужно, это исключительно в этом типе, чтобы не отображать столбец базового идентификатора. В Katalog мне нужно свойство enum id.

РЕДАКТИРОВАТЬ 1: проверив ответ, я узнал, что проблема возникла в Seed-Method. У меня было это Семя:

    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
    }

Я использовал метод AddOrUpdate из DbSetMigrationsExtensions, как это рекомендуется в сгенерированном комментарии. Но особенно в этом случае есть ошибка. Если я использую обычный метод Add и SaveChanges, он работает.

Спасибо за помощь. Я отмечу данный ответ как ответ, потому что он указал мне правильное направление.

Nico

1 Ответ

0 голосов
/ 15 ноября 2018

Я могу заставить его работать с 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, я не мог перестать жаловаться на несоответствующий тип.Я попытался [NotMapped] на «новом» свойстве подкласса, но затем он, похоже, проигнорировал определение Key.

В конечном итоге это будет причиной не расширения базового класса для этого типа сущности.Базовые классы предназначены для классов, которые имеют идентичные свойства и поведение.Как только вам нужно отклониться от этого, сущность больше не является частью этого общего набора.Как правило, это признак преждевременной оптимизации или согласованности ради согласованности.(который я рассматриваю как анти-паттерны) Создайте его для работы, затем оптимизируйте по шаблонам, чтобы уменьшить дублирование и т. д. Обычно получается более качественный код, чем попытка написать его оптимально, а затем де-оптимизировать или взломать это предположение, когда что-то не так.поместиться.:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...