Добавление префиксов в имена таблиц приводит к удалению столбца дискриминатора

#c# #entity-framework #entity-framework-6

#c# #entity-framework #entity-framework-6

Вопрос:

У меня есть таблица поиска, которая довольно проста

 public class LookupType : Entity
{
    public LookupType()
    {
    }

    public LookupType(string value)
    {
        Value = value;
    }

    public string Value { get; set; }

    // A few other properties
}
  

И несколько классов, которые наследуют от него

 public class SomeType : LookupType
{
    public SomeType() 
    {
    }

    public SomeType(string value) 
        : base(value)
    {
    }
}
  

У меня также есть следующее сопоставление для типов поиска в OnModelCreating методе.

 // Lookup Types
modelBuilder.Entity<LookupType>()
            .Map<SomeType>(m => m.Requires("LookupType").HasValue("Some Type"));
  

Теперь это отлично работает для того, что мне нужно. Миграция создаст таблицу вместе со столбцом LookupType в качестве дискриминатора.

 CreateTable(
            "dbo.LookupTypes",
            c => new
                {
                    Id = c.Int(nullable: false, identity: true),
                    DisplayOrder = c.Int(nullable: false),
                    Value = c.String(),
                    TimeStamp = c.Binary(nullable: false, fixedLength: true, timestamp: true, storeType: "rowversion"),
                    LookupType = c.String(maxLength: 128),
                })
            .PrimaryKey(t => t.Id);
  

Однако мне нужно добавить префиксы в имена таблиц. Итак, в OnModelCreating методе моего контекста я добавляю следующую строку

 modelBuilder.Types().Configure(entity => entity.ToTable("abc_"   entity.ClrType.Name));
  

При LookupType создании миграций столбец теперь отсутствует.

 CreateTable(
            "dbo.abc_LookupType",
            c => new
                {
                    Id = c.Int(nullable: false, identity: true),
                    DisplayOrder = c.Int(nullable: false),
                    Value = c.String(),
                    TimeStamp = c.Binary(nullable: false, fixedLength: true, timestamp: true, storeType: "rowversion"),
                })
            .PrimaryKey(t => t.Id);
  

Я знаю, что конфигурация префикса — это строка, которая вызывает проблемы, потому что ее комментирование и повторная миграция вернут столбец LookupType обратно.

Определения столбцов не должны меняться, так почему удаляется столбец дискриминатора? Есть ли какой-либо способ обойти это, чтобы я мог сохранить столбец дискриминатора и добавить префикс к таблицам?

Ответ №1:

Я думаю, вам нужно указать наследование таблицы для каждой иерархии (TPH) в OnModelCreating:

 public class FooDb : DbContext
    {
        public FooDb()
            : base("name=DefaultConnection")
        { }

        public DbSet<BarTypeA> BarTypesA { get; set; }
        public DbSet<BarTypeB> BarTypesB { get; set; }
        public DbSet<BarTypeC> BarTypesC { get; set; }



        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {


            modelBuilder.Entity<Foo>()
            .Map<LookupType>(m => m.Requires("xyx"   "FooType").HasValue("L"))
            .Map<BarTypeA>(m => m.Requires("xyx"   "LookupType").HasValue("A"))
            .Map<BarTypeB>(m => m.Requires("xyx"   "LookupType").HasValue("B"))
            .Map<BarTypeC>(m => m.Requires("xyx"   "LookupType").HasValue("C"));


        }
    }
  

Граф объекта выглядит следующим образом и заполняет его данными (не использовался начальный метод):

 public class Foo
    {
        public int Id { get; set; }
        public int DisplayOrder { get; set; }
        public string Description { get; set; }
        public string Package { get; set; }
        public Byte[] TimeStamp { get; set; }
    }

    public class LookupType : Foo
    {
        public LookupType(){}

        public LookupType(string value)
        {
            Description = value;
        }

        public string Description { get; set; }
        // A few other properties
    }

    public class BarTypeA : LookupType
    {
        public BarTypeA() { }
        public BarTypeA(string value) : base(value) { }
    }

    public class BarTypeB : LookupType
    {
        public BarTypeB() { }
        public BarTypeB(string value) : base(value) { }
    }

    public class BarTypeC : LookupType
    {
        public BarTypeC() { }
        public BarTypeC(string value) : base(value) { }
    }
  

консольное приложение

 static void Main(string[] args)
    {

        using (var db = new FooDb())
        {
            List<Foo> foos = new List<Foo>(){
                new BarTypeA ("peanutsA"){ DisplayOrder=100,Package="packA"},
                new BarTypeA ("olivesA"){ DisplayOrder = 101,Package="packB" },
                new BarTypeB ("peanutsB"){ DisplayOrder = 200,Package="packC" },
                new BarTypeB ("olivesB"){ DisplayOrder = 201,Package="packD" },
                new BarTypeC ("peanutsC"){ DisplayOrder = 300,Package="packE" },
                new BarTypeC ("olivesC"){ DisplayOrder = 301,Package="packF" }
            };

            db.BarTypesA.Add((BarTypeA)foos[0]);
            db.BarTypesA.Add((BarTypeA)foos[1]);
            db.BarTypesB.Add((BarTypeB)foos[2]);
            db.BarTypesB.Add((BarTypeB)foos[3]);
            db.BarTypesC.Add((BarTypeC)foos[4]);
            db.BarTypesC.Add((BarTypeC)foos[5]);
            db.SaveChanges();
        }
        Console.WriteLine("Press any key to end");
        Console.ReadLine();

    }
  

Сгенерированная таблица в БД :
Идентификатор, порядок отображения, Описание, Пакет, временная метка, xyxFooType,xyxLookupType
1 100 NULL packA NULL NULL A
2 101 NULL packB NULL NULL A
3 200 NULL packC NULL NULL B
4 201 NULL packD NULL NULL B
5 300 NULL packE NULL NULL C
6 301 NULL packF NULL NULL C

и, наконец, начальный набор add-migrations выглядит следующим образом:

 CreateTable(
            "dbo.Foos",
            c => new
                {
                    Id = c.Int(nullable: false, identity: true),
                    DisplayOrder = c.Int(nullable: false),
                    Description = c.String(),
                    Package = c.String(),
                    TimeStamp = c.Binary(),
                    xyxFooType = c.String(maxLength: 128),
                    xyxLookupType = c.String(maxLength: 128),
                })
            .PrimaryKey(t => t.Id);
  

Жаль, что Microsoft не может найти ресурс для тщательного документирования и предоставления образцов, поскольку EF кажется таким мощным. Не уверен, что приведенное выше соответствует вашему сценарию, но, безусловно, оно генерирует полезный столбец дискриминатора xyzLookupType. Возникли проблемы с файлами миграции db-кеши debug / obj не синхронизированы. Все еще ищу хорошую документацию / книги.
Не совсем понимаю, почему описание не добавляется в таблицу, возможно, это связано с тем, что я добавляю BarTypes, а не корневые типы (могут потребоваться виртуальные свойства). Также может потребоваться добавить наборы баз данных для предков…

Ответ №2:

По-видимому, вы не можете указать какие-либо пользовательские сведения о сопоставлении для таблицы для наследования иерархии без переключения Entity Framework на таблицу для каждого типа.

Самым простым решением было просто добавить .ToTable("abc_LookupTypes")

 // Lookup Types
modelBuilder.Entity<LookupType>()
        .Map<SomeType>(m => m.Requires("LookupType").HasValue("Some Type"))
        .ToTable("abc_LookupTypes");
  

Затем Entity Framework переключается обратно на TPH. Избыточно для строки выше, но работает без необходимости добавлять унаследованные типы в контекстный файл.