Entity Framework Code First: как смоделировать отношения «клиент/адрес»?

Вот моя упрощенная модель:

public class Customer
{
    public int ID { get; set; }
    public int MailingAddressID { get; set; }
    [ForeignKey("MailingAddressID")]
    public Address MailingAddress { get; set; }

    public virtual ICollection<Address> Addresses { get; set; }
}

public class Address
{
    public int ID { get; set; }
    public int CustomerID { get; set; }
    [ForeignKey("CustomerID")]
    public Customer Customer { get; set; }
}

Когда я пытаюсь создать базу данных, я получаю следующую ошибку:

Введение ограничения FOREIGN KEY «Customer_MailingAddress» в таблице «Customers» может вызвать циклы или несколько каскадных путей. Укажите ON DELETE NO ACTION или ON UPDATE NO ACTION или измените другие ограничения FOREIGN KEY. Не удалось создать ограничение. См. предыдущие ошибки.

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

Это соответствует моему дизайну, потому что если у клиента есть один или несколько адресов, то один из них должен быть почтовым адресом, и этот адрес нельзя удалить.

Итак, что мне здесь не хватает? Спасибо!

Изменить:

Забыл упомянуть, что я пытался добавить следующую строку в метод OnModelBuilding:

modelBuilder.Entity<Customer>().Property(x => x.MailingAddressID).IsOptional();

Это позволяет создать базу данных, однако при добавлении клиента я получаю следующую ошибку:

Оператор INSERT конфликтовал с ограничением FOREIGN KEY «Customer_MailingAddress». Конфликт произошел в базе данных «DomainModel.SeasideHeightsEntities», таблице «dbo.Addresses», столбце «ID». Заявление было прекращено.

Все еще в недоумении, как правильно смоделировать это.


person Jeff Camera    schedule 01.03.2011    source источник


Ответы (1)


Проблема в том, что удаляется первым: клиент или почтовый адрес? Вы не можете удалить их оба одновременно, удаление будет происходить последовательно. Когда первый удаляется, он нарушает правило, потому что второй еще не удален.

Из того, что я вижу в вашей модели, я бы не стал использовать внешние ключи для обработки этой логики, я бы обработал ее во время проверки объекта, поместив атрибут [Required] в свойство MailingAddress вместо внешнего ключа.

Вам также следует рассмотреть дополнительную логику реализации, чтобы гарантировать, что MailingAddress является частью коллекции Addresses.

person Paul    schedule 01.03.2011
comment
Ни один из них не должен быть удален, пока у клиента есть почтовый адрес! Это одна из причин, почему я думаю, что отношения с FK имеют смысл. Это отлично работало в моей обычной программе EF для базы данных. Любые предложения о том, как я мог бы реализовать это с помощью подхода «сначала код»? Спасибо! - person Jeff Camera; 01.03.2011
comment
Я с уважением не согласен. Что-то должно владеть отношениями. В этом случае мне кажется, что Заказчик является агрегатом домена и, следовательно, должен нести ответственность за контроль над своим почтовым адресом. - person Paul; 01.03.2011
comment
Я вижу, как это имеет смысл. В таком случае знаете ли вы, можно ли через CTP Fluent API указать, что при удалении клиента он также должен удалить связанный с ним почтовый адрес (или другие объекты, которыми он владеет)? - person Jeff Camera; 01.03.2011
comment
да, это часть API-интерфейса Fluent, когда вы вызываете API-интерфейс Fluent по своей ссылке, у него есть метод WillCascadeOnDelete(), подробный код см. в этой статье: weblogs.asp.net/manavi /архив/2010/12/19/ - person Paul; 01.03.2011