EF6: расщепление таблицы не работает

Я пытаюсь создать базу данных EF6, в которой две таблицы, адреса и посещения, имеют одинаковые значения с первичными ключами. Посещения, концептуально, являются продолжением Адреса. Я делю таблицы, потому что большинство записей в Адресе не требуют полей, содержащихся в Посещениях.

Я использую код первый подход. Вот соответствующий код для адресов:

    public class Address 
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }

    [ForeignKey( "ID" )]
    public virtual Visit Visit { get; set; }

и для посещений:

   public class Visit
   {
    [Key]
    [DatabaseGenerated( DatabaseGeneratedOption.Identity )]
    public int ID { get; set; }

    [ForeignKey("ID")]
    public virtual Address Address { get; set; }

Основываясь на моих исследованиях, мне также нужно было включить в метод OnModelCreating моего datacontext следующее:

    modelBuilder.Entity<Visit>()
        .HasOptional( v => v.Address )
        .WithRequired();

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

Неверное имя столбца 'Address_ID'. Неверное имя столбца 'Address_ID'.

Из моего ограниченного опыта работы с EF6 это выглядит как-то глубоко внутри фреймворка, где он ожидает, что будут поля с именем 'Address_ID', возможно, в таблице посещений (на основе структуры имен 'table name'_'field name', которую я видел для другие неявно добавленные поля).

Возможно ли то, что я пытаюсь сделать? Если так, что я пропускаю в конфигурации?

Дополнительная информация

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

разрешение

В конце концов я сделал то, что должен был сделать ранее, то есть изучил фактический код T-SQL, сгенерированный взрывающимся запросом. Оказывается, проблема была не в связи между визитом и адресом, а в совершенно разных отношениях, связанных с другой таблицей. По-видимому, где-то по пути я что-то сделал, чтобы EF подумал, что другая таблица (Избиратели) имеет поле внешнего ключа Address_ID. На самом деле отношение адрес / избиратель должно было быть и изначально было связано с полем Voter.AddressID.

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

Для полноты, вот код, который мне пришлось вставить в вызов метода OnModelCreating, чтобы отношения Address/Visit работали правильно:

modelBuilder.Entity<Visit>()
    .HasRequired( v => v.Address )
    .WithRequiredDependent( a => a.Visit );

modelBuilder.Entity<Address>()
    .HasRequired( a => a.Visit )
    .WithRequiredPrincipal( v => v.Address );

Меня немного смущает, почему я должен использовать HasRequired, чтобы иметь возможность использовать WithRequiredPrincipal/WithRequiredDependent, поскольку не каждая запись в таблице адресов имеет запись в таблице посещений. Это может показаться "необязательным", а не "обязательным". Но, похоже, это работает, и, возможно, "требуемая" часть является внутренней только для модели базы данных EF, а не для самой базы данных.

2 ответа

Решение

В модели есть 2 проблемы:
- Только один из ключей может иметь автонумерацию, другой должен получить тот же Id (независимо от EF).
- Проблема с отображением.
Эта модель должна работать.

public class Address
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public string Description { get; set; }

    public virtual Visit Visit { get; set; }
}

public class Visit
{
    public Visit()
    {
        Address = new Address();
    }

    [Key]
    [ForeignKey("Address")]
    public int Id { get; set; }

    public string Description { get; set; }

    public virtual Address Address { get; set; }
}

Пример использования

            var visit = new Visit
            {
                Description = "Visit",
                Address = {Description = "AddressDescription"}
            };

            db.Visits.Add(visit);

            db.SaveChanges();

В дополнение к тому, что упомянул Буби, ваш modelBuilder утверждение противоречит модели в том, что оно не упоминает Address.Visit как обратное свойство. Таким образом, он думает, что свойство представляет собой отдельное отношение и пытается создать Address_ID столбец для этих отношений.

Тебе нужно иметь

modelBuilder.Entity<Visit>()

    // from your description sounds like every Visit needs an Address
    .HasRequired(v => v.Address )

    // need to mention the inverse property here if you have one
    .WithOptional(a => a.Visit); 

... или просто полностью удалите оператор, так как вы уже используете атрибуты, и EF сможет разобраться с ним по соглашению.

Другие вопросы по тегам