Чтобы избежать использования таблицы для иерархии (TPH), я рассматривал примеры того, как лучше всего реализовать Table-Per-Concrete Class (TPC) в моей модели базы данных. Я наткнулся на official documentation и this article.Наследование на конкретный тип (TPC) в Entity Framework 6 (EF6)
Ниже приведены некоторые макеты классов с некоторым простым наследованием.
public class BaseEntity
{
public BaseEntity()
{
ModifiedDateTime = DateTime.Now;
}
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public DateTime ModifiedDateTime { get; set; }
}
public class Person : BaseEntity
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Business : BaseEntity
{
public string Name { get; set; }
public string Location { get; set; }
}
Конфигурации DbModelBuilder, используемые в примерах в обеих статьях.
modelBuilder.Entity<BaseEntity>()
.Property(c => c.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
modelBuilder.Entity<Person>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Person");
});
modelBuilder.Entity<Business>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Business");
});
Приложение работает успешно, но когда я иду обратно в базу данных я нахожу три (3) таблицы вместо двух (2) Я ожидал найти. После небольшого тестирования появится таблица «BaseEntity», но она никогда не используется. Кажется, все работает отлично, за исключением пустой пустой оси.
Я общаюсь с конфигурациями DbModelBuilder, в итоге удаляя конфигурации «BaseEntity», которые обеспечивают ожидаемый результат; Две (2) таблицы, каждая из которых имеет правильные свойства и работает правильно.
Я делаю последнее испытание, уничтожаю все конфигурации DbModelBuilder, включаю только два свойства (2) DbSet для «Личность» и «Бизнес» и снова тестирую.
public DbSet<Person> People { get; set; }
public DbSet<Business> Businesses { get; set; }
К моему удивлению, проект строит, выходит в базу данных, создает только две таблицы со всеми свойствами класса, включая унаследованные от них из класса «BaseEntity». Я могу делать операции CRUD без проблем.
После запуска многих тестов я не могу найти никаких проблем с окончательным тестом, и я не смог воспроизвести дублируемую ключевую ошибку, о которой сообщали обе статьи.
Изменения в базе данных были успешно завершены, но при обновлении контекста объекта произошла ошибка . Объект ObjectContext может быть в несогласованном состоянии. Внутреннее сообщение об исключении: AcceptChanges не может продолжаться, потому что ключевые значения объекта конфликтуют с другим объектом в ObjectStateManager. Перед вызовом AcceptChanges убедитесь, что значения клавиш равны .
- Мне любопытно, почему примеры используют свойство MapInheritedProperties; это устаревший метод?
- Почему оба примера говорят о включении свойств конфигурации для «BaseEntity», но в то же время они включают либо свойство DbSet, либо любые конфигурации DbModelBuilder для класса «BaseEntity» заставляют создать неиспользуемую таблицу.
- В отношении уникальной ключевой ошибки, о которой предупреждали статьи; Я не могу воспроизвести ошибку, и я много раз тестировал первичный ключ как int, сгенерированный базой данных, так и директив, сгенерированный базой данных. Является ли информация об этой ошибке также устаревшей или есть тест, который я могу запустить, чтобы произвести указанную ошибку?
Я думаю, что должно быть создано 3 таблицы, хотя базовый кажется непригодным. это некоторые недостатки TPC, вы можете воспользоваться некоторыми преимуществами в клиентском коде, но должны пострадать от некоторых избыточных данных (которые не должны быть даже созданы, как в традиционной концепции проектирования баз данных). Я думаю, вы можете попробовать TPT, тогда как базовая таблица содержит все общие столбцы, и это больше не будет считаться избыточным. – Hopeless
@Hopeless Причина, по которой я не рассматривал TPT, насколько я обожаю дизайн, являющийся OCD, как и я, - это производительность, которую вы выбрали из всех операторов соединения, необходимых для отвлечения даже немного сложных данных. Что касается утверждения о трех таблицах, я видел много статей об обратном, но опять-таки я не смог нормально работать. Мне интересно, есть ли какой-то недостаток для окончательного способа настройки моделей; Я столкнулся с двумя таблицами, без ненужных таблиц, без ненужных столбцов, с первичными ключевыми проблемами, но не могу найти примеров, которые я делал. – Nicholas
Для TPH класс BaseEntity должен быть абстрактным. Я думаю, что только один должен генерировать только два таблицы DB для конкретных типов. Я действительно столкнулся с тем, что этот объект ObjectContext находится в ошибке несогласованного состояния, и единственным способом, который я смог исправить, является создание поля Id в типе BaseEntity Guid вместо Int (что кажется довольно расточительным). – blgrnboy